析构函数C++中的异常

ami*_*ngh 36 c++ destructor exception-handling

我很清楚,不应该在析构函数中抛出任何异常.

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

#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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

30
exception caught
Run Code Online (Sandbox Code Playgroud)

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

Vit*_*meo 63

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

将保证std::terminate将被召唤.在这种情况下,a将被销毁并将在处理另一个异常时抛出.

活coliru的例子


附加信息:


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

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

main.cpp:16:15:警告:throw将始终调用terminate()[ - Wminminate]

     throw 30;

           ^~
Run Code Online (Sandbox Code Playgroud)

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

抛出'int'实例后调用terminate

bash:第7行:1505 Aborted(core dumped)./a.out

如编译器输出中所示,因为C++ 11 析构函数是隐式的noexcept(true).如果要阻止此行为,可以将其标记为noexcept(false).例:

~A() noexcept(false)
{
    throw 30;
}
Run Code Online (Sandbox Code Playgroud)

在coliru上的现场例子


Eya*_*sSH 10

在您的示例中,A()构造一个临时变量,A然后立即对其进行破坏.因此throw 10;从未执行过.

发生的throw声明是在析构函数中A.执行时A::~A(),程序不会在该点退绕(即从异常中清除状态).例如,请参阅"抛出的析构函数".