我很清楚,不应该在析构函数中抛出任何异常。
但作为掌握这一概念的一部分,我编写了这个例子: -
#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()来终止,因为同时会有两个例外。但是,该程序提供以下输出: -
30
exception caught
任何人都可以向我解释这背后的逻辑,为什么这不会终止?
答案 0 :(得分:62)
std::terminate
。这意味着如果在处理另一个异常时调用异常,则会调用std::terminate
。
在您的示例中,这不会发生 - A();
将构建并立即销毁 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
将被销毁并在处理另一个异常时抛出 。
其他信息:
请注意std::terminate
并提供警告:
main.cpp:在析构函数'A :: ~A()'中:
main.cpp:16:15:警告:throw将始终调用terminate() [-Wterminate]
throw 30; ^~
main.cpp:16:15:注意:在C ++ 11析构函数中默认为noexcept
在抛出&#39; int&#39;
的实例后终止调用bash:第7行:1505 Aborted(core dumped)./a.out
如编译器输出中所示,由于C ++ 11 析构函数是隐式noexcept(true)
。如果要阻止此行为,只需将其标记为noexcept(false)
即可。例如:
~A() noexcept(false)
{
throw 30;
}
答案 1 :(得分:10)
在您的示例中,A()
为A
构造临时变量,然后立即对其进行破坏。因此永远不会执行throw 10;
。
throw
语句发生在A
的析构函数中。执行A::~A()
时,程序不会在该点退绕(即从异常中清除状态)。例如,请参阅"Destructors that throw"。