为什么析构函数不被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 ++ Optimizing Compiler Version 14.00.50727.762 for 80×86”。命令行是cl /EHa my.cpp

编译器和往常一样吗? 标准在这个问题上说什么?

析构函数没有被调用,因为未处理的exception的terminate()在堆栈解开之前被调用。

C ++规范说明的具体细节超出了我的理解,但是使用gdb和g ++的debugging跟踪似乎certificate了这一点。

根据标准草案第15.3节第9点:

 9如果程序中找不到匹配的处理程序,则函数terminate()
   (_except.terminate_)被调用。 堆栈是否被解开
  在调用terminate()之前是实现定义的。

C ++语言规范指出: 调用在从try块到throw-expression的path上构造的自动对象的析构函数的过程称为“堆栈展开”。您的原始代码不包含try块,这就是为什么堆栈展开没有发生。

在第二个例子中,当它离开try {}模块时,dtor被调用。

在第一个例子中,当离开main()函数后程序closures时,dtor被调用,此时cout可能已经被销毁。

我也假定编译器不会生成相对于“a”的代码,因为它没有被引用,但是仍然不正确,因为析构函数需要执行某些操作。

所以,我试过在VS2008 / vc9(+ SP1),debugging和发布和〜A被抛出后,调用超出f() – 这是正确的行为,如果我是正确的。

现在我只是尝试了VS2005 / vc8(+ SP1),这是相同的行为。

我用断点来确定。 我只是检查了控制台,我也有“〜A”的消息。 也许你在其他地方做错了?

这个问题很容易谷歌,所以我在这里分享我的情况。

确保yor exeption不跨越“ extern "C"边界或使用MSVC选项/ EHs(使用Extern C函数(/ EHs)启用C ++ exeptions = Yes)

对不起,我没有这个标准的副本。
我肯定会喜欢这个的明确答案,所以有标准副本的人想要分享关于发生什么的章节和诗句:

从我的理解终止只是叫做iff:

  • exception处理机制无法find引发exception的处理程序。
    以下是更具体的例子:
    • 在堆栈展开期间,exception转义析构函数。
    • 抛出的expression式,exception转义构造函数。
    • exception转义非本地静态(即全局)的构造/析构函数
    • exception转义了用atexit()注册的函数。
    • 一个exception转义main()
  • 尝试重新抛出exception,当没有exception正在传播。
  • 意外的exception使用exception说明符(通过意外)
Interesting Posts