为什么异常时不调用析构函数?
-
03-07-2019 - |
题
我期望 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 If no matching handler is found in a program, the function terminate() (_except.terminate_) is called. Whether or not the stack is unwound before calling terminate() is implementation-defined.
其他提示
C ++语言规范声明: 调用从try块到throw-expression的路径上构造的自动对象的析构函数的过程称为&#8220;堆栈展开。&#8221; 您的原始代码不包含try块,这就是为什么不会发生堆栈展开的原因。
我也假设编译器没有生成相对于“a”的代码。因为它没有被引用但仍然是正确的行为,因为析构函数会执行必须执行的操作。
所以,我尝试在VS2008 / vc9(+ SP1),调试和发布中,在抛出异常后调用~A,退出f() - 这是正确的行为,如果我是对的。
现在我尝试使用VS2005 / vc8(+ SP1)并且它的行为相同。
我使用了断点来确定。我刚用控制台检查过,我有“~A”消息也是。也许你在其他地方做错了?
抱歉,我身上没有该标准的副本。
我肯定想要一个明确的答案,因此拥有该标准副本的人希望分享有关正在发生的事情的章节和诗句:
据我了解,终止仅称为 iff:
- 异常处理机制找不到抛出的异常的处理程序。
以下是更具体的案例:- 在堆栈展开期间,异常会从析构函数中逃脱。
- 抛出的表达式、异常会从构造函数中转义。
- 异常转义非局部静态(即全局)的构造函数/析构函数
- 异常会转义使用 atexit() 注册的函数。
- main() 中出现异常
- 当当前没有异常传播时尝试重新抛出异常。
- 意外异常使用异常说明符转义函数(通过意外)
这个问题很容易谷歌,所以我在这里分享我的情况。
确保yor exeption不跨越 extern&quot; C&quot;
边界或使用MSVC选项/ EHs(启用C ++ exeptions = Yes with Extern C functions(/ EHs))
在第二个示例中,dtor在离开try {}块时被调用。
在第一个例子中,当程序在离开main()函数后关闭时调用dtor --- cout可能已经被销毁了。