Exception in Destructor C++

2019-03-17 04:01发布

问题:

I am well aware of the fact that one should not throw any exception in destructor.

But as a part of making my grip on this concept,I coded this example :-

#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;
    }
}

As per my understanding, this program should be terminated by calling std::terminate() as there will be two exceptions at the same time. But, this program is giving the following output:-

30
exception caught

Can anyone please explain me the logic behind this as to why this is not terminating?

回答1:

std::terminate will be called if an exception is thrown during stack unwinding. That means that if an exception is called while another exception is being handled, then std::terminate will be called.

In your example, that doesn't happen - A(); will construct and immediately destroy an instance of A. The throw 30 will then be caught correctly.

Changing your code to:

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;
    }
}

will guarantee that std::terminate will be called. In this case, a will be destroyed and will throw while another exception is being handled.

live coliru example


Additional information:

  • cppreference/Destructors/Exceptions

  • StackOverflow: "throwing exceptions out of a destructor"


Note that in C++11 and above, your code snippet will call std::terminate and provide you a warning:

main.cpp: In destructor ‘A::~A()’:

main.cpp:16:15: warning: throw will always call terminate() [-Wterminate]

     throw 30;

           ^~

main.cpp:16:15: note: in C++11 destructors default to noexcept

terminate called after throwing an instance of 'int'

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

As seen in the compiler output, since C++11 destructors are implicitly noexcept(true). If you want to prevent this behavior, you can simply mark them as noexcept(false). Example:

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

live example on coliru



回答2:

In your example, A() construct a temporary variable for A then destructs it immediately. Thus throw 10; is never executed.

The throw statement taking place is in the destructor for A. When executing A::~A(), the program is not unwinding (i.e. cleaning up state from an exception) at that point. See "Destructors that throw" for example.