析构函数C ++中的异常

时间:2017-03-23 12:45:05

标签: c++ exception-handling destructor

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

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

#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

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

2 个答案:

答案 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将被销毁并在处理另一个异常时抛出

live coliru example

其他信息:

请注意中的,您的代码段会调用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;
}

live example on coliru

答案 1 :(得分:10)

在您的示例中,A()A构造临时变量,然后立即对其进行破坏。因此永远不会执行throw 10;

throw语句发生在A的析构函数中。执行A::~A()时,程序不会在该点退绕(即从异常中清除状态)。例如,请参阅"Destructors that throw"