析构函数C ++中的exception

我很清楚,不应该在析构函数中抛出任何exception。

但是作为抓住这个概念的一部分,我编码了这个例子:

#include <iostream> using namespace std; class A { private: int i; public: A() { i = 10; } ~A() { throw 30; } }; int main(){ try{ A(); throw 10; } catch (int i){ cout << i << endl; cout << "exception caught" << endl; } } 

根据我的理解,这个程序应该通过调用std :: terminate()来终止,因为同时会有两个exception。 但是,这个程序是给出以下输出:

 30 exception caught 

任何人都可以请解释这背后的逻辑为什么这不是终止?

如果在堆栈展开期间引发exception, std::terminate将被调用。 这意味着,如果在处理另一个exception时调用exception ,则将调用std::terminate

在你的例子中,这不会发生 – A(); 将构build并立即销毁 A一个实例。 throw 30将被正确地抓住。

将您的代码更改为:

 int main(){ try{ A a; // begin `a` lifetime throw 10; // | throw #0 // | end `a` lifetime // throw #1 } catch(int i){ cout<<i<<endl; cout<<"exception caught"<<endl; } } 

将保证std::terminate将被调用。 在这种情况下, a将被销毁,并在处理另一个exception时抛出。

活的coliru例子


附加信息:

  • cppreference /parsing器/exception

  • StackOverflow:“从析构函数中抛出exception”


请注意, 在C ++ 11及更高版本中 ,您的代码片段将调用std::terminate并提供警告:

main.cpp:在析构函数A ::〜A()中:

main.cpp:16:15:warning:throw将始终调用terminate()[-Wterminate]

  throw 30; ^~ 

main.cpp:16:15:注意: 在C ++ 11中,析构函数默认为noexcept

抛出'int'实例后终止调用

bash:第7行:1505 Aborted(核心转储).a.out

正如在编译器输出中看到的那样,因为C ++ 11的析构函数隐含地是noexcept(true) 。 如果你想防止这种行为,你可以简单地将它们标记为noexcept(false) 。 例:

 ~A() noexcept(false) { throw 30; } 

在coliru生活的例子

在你的例子中, A()A构造一个临时variables,然后立即破坏它。 这样throw 10; 永远不会执行。

throw语句发生在A的析构函数中。 当执行A::~A() ,程序不会退出(即从exception中清除状态)。 例如请参阅“破坏者” 。