为什么异常时不调用析构函数
Why destructor is not called on exception?
我希望在这个程序中调用A::~A()
,但它不是:
#include <iostream>
struct A {
~A() { std::cout << "~A()" << std::endl; }
};
void f() {
A a;
throw "spam";
}
int main() { f(); }
但是,如果我将最后一行更改为
int main() try { f(); } catch (...) { throw; }
然后调用A::~A()
。
我正在使用Visual Studio 2005中的"Microsoft(R)32位C/C++优化编译器版本14.00.50727.762 for 80x86"进行编译。命令行cl /EHa my.cpp
。
编译器像往常一样正确吗?标准对此事有何规定?
不调用析构函数,因为在堆栈展开之前调用了未处理异常的 terminate()。
C++规范所说的具体细节超出了我的知识范围,但 gdb 和 g++ 的调试跟踪似乎证实了这一点。
根据标准草案第15.3节第9点:
9 如果在程序中找不到匹配的处理程序,则函数 terminate() (_except.终止_) 被调用。 堆栈是否展开 在调用 terminate() 之前是实现定义的。
C++语言规范指出:为从 try 块到抛出表达式的路径上构造的自动对象调用析构函数的过程称为"堆栈展开"。您的原始代码不包含 try 块,这就是为什么堆栈展开不会发生的原因。
我没有标准的副本。
我肯定想要一个明确的答案,所以有标准副本的人想分享关于发生的事情的章节和经文:
据我了解,终止只叫 iff:
- 异常
- 处理机制找不到引发的异常的处理程序。
以下是更具体的情况:- 在堆栈展开期间,异常会转义析构函数。
- 抛出的表达式,异常转义构造函数。
- 异常转义了非本地静态(即全局)的构造函数/析构函数
- 异常转义了使用 atexit() 注册的函数。
- 异常转义 main()
- 尝试在当前没有异常传播时重新引发异常。
- 意外异常使用异常说明符转义函数(通过意外)
在第二个示例中,当 dtor 离开 try{} 块时,将调用它。
在第一个示例中,当程序在离开main()函数后关闭时调用dtor---此时cout可能已被销毁。
我也假设编译器不会生成相对于"a"的代码,因为它没有被引用,但它仍然不是正确的行为,因为析构函数做了一些必须执行的事情。
所以,我尝试在VS2008/vc9(+SP1)中调试和发布,并在抛出异常后调用~A,退出f() - 如果我是对的,这是正确的行为。
现在我刚刚尝试使用VS2005/vc8(+SP1),这是相同的行为。
我使用断点来确定。我刚刚检查了控制台,我也有"~A"消息。也许你在别的地方做错了?
这个问题很容易谷歌,所以我在这里分享我的情况。
确保 yor exeption 不会越过边界extern "C"
或使用 MSVC 选项/EH(使用 Extern C 函数 (/EH) 启用 C++ exeptions = 是)
- 什么时候调用析构函数
- C++-明确何时以及如何调用析构函数
- C++ 防止在映射中放置()时调用析构函数
- 调用析构函数以释放动态分配的内存
- C++:使用方法调用析构函数的顺序是什么?
- 向量推回调用析构函数时调用析构函数
- 如何在调用析构函数时优雅地停止/销毁带有阻塞调用C++线程?
- C++,我应该调用析构函数吗?
- 如何获取有关在 Clang LibTooling 中调用析构函数的信息?
- 当我从 std::vector 中的新放置调用析构函数时会发生什么?
- 为什么这里不调用析构函数
- 在调用 std::bind 的产品后意外调用析构函数
- 为什么在传递给函数而不是构造函数时调用析构函数?
- 如何在C++中调用析构函数
- 为什么为未删除的对象调用析构函数?
- 调用析构函数时出错
- C++ 在不释放内存的情况下调用析构函数
- 为什么在运算符删除中不调用析构函数?
- C++ 调用析构函数后动态模板队列"double free or corruption (out)"
- 在 postOrderDelete 上调用析构函数时引发的异常