我希望在这个程序中调用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
。
编译器是否正常?标准在这件事上说了些什么?
答案 0 :(得分:65)
没有调用析构函数,因为在堆栈展开之前调用了未处理异常的terminate()。
C ++规范所说的具体细节不在我的掌握之中,但是使用gdb和g ++的调试跟踪似乎证实了这一点。
根据draft standard第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.
答案 1 :(得分:14)
C ++语言规范声明: 为从try块到throw-expression的路径构造的自动对象调用析构函数的过程称为“堆栈展开”。 您的原始代码不包含try块,这就是为什么不会发生堆栈展开的原因。
答案 2 :(得分:2)
我也假设编译器没有生成相对于“a”的代码,因为它没有被引用但是,它仍然是正确的行为,因为析构函数会执行必须执行的操作。
所以,我尝试在VS2008 / vc9(+ SP1),调试和发布中,在抛出异常后调用~A,退出f() - 这是正确的行为,如果我是对的。< / p>
现在我尝试使用VS2005 / vc8(+ SP1)并且它的行为相同。
我使用了断点来确定。我刚用控制台检查过,我也收到了“~A”的消息。也许你在其他地方做错了?
答案 3 :(得分:2)
对不起我没有关于我的标准副本。
我肯定希望得到一个明确的答案,所以有标准副本的人想分享有关发生的章节和经文:
根据我的理解,终止只被称为iff:
答案 4 :(得分:2)
这个问题很容易谷歌,所以我在这里分享我的情况。
确保yor exeption不跨越extern "C"
边界或使用MSVC选项/ EHs(使用Extern C函数(/ EHs)启用C ++ exeptions = Yes)
答案 5 :(得分:1)
在第二个示例中,dtor在离开try {}块时被调用。
在第一个例子中,当程序在离开main()函数后关闭时调用dtor --- cout可能已经被销毁了。