为什么我的析构函数中的异常没有触发 std::终止?

Why is my exception-in-destructor not triggering std::terminate?

本文关键字:std 终止 析构函数 我的 异常 为什么      更新时间:2023-10-16

我很清楚这样一个事实,即不应该在析构函数中抛出任何异常。

但作为掌握这个概念的一部分,我编写了这个例子:-

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

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

30
exception caught

谁能解释一下为什么这没有终止背后的逻辑?

如果在堆栈展开过程中抛出异常,将调用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将被销毁,并在处理另一个异常时抛出。

活科里鲁示例


附加信息:

  • cpp 首选项/析构函数/异常

  • StackOverflow:"从析构函数中抛出异常">


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

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

主.cpp:16:15: 警告:抛出将始终调用终止() [-终止]

throw 30;
^~

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

抛出"int"实例后调用的终止

bash:第 7 行:1505 中止(核心转储)./a.out

如编译器输出所示,由于 C++11析构函数隐式noexcept(true).如果要防止此行为,只需将它们标记为noexcept(false).例:

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

科里鲁的现场例子

在您的示例中,A()构造一个临时变量,然后立即销毁它A。因此,throw 10;永远不会被执行。

throw发生的语句位于A的析构函数中。当执行A::~A()时,程序不会在这一点上展开(即从异常中清除状态)。例如,请参阅"抛出的析构函数"。