Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception in Destructor C++

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?

like image 653
amit singh Avatar asked Mar 23 '17 12:03

amit singh


2 Answers

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

like image 127
Vittorio Romeo Avatar answered Nov 09 '22 19:11

Vittorio Romeo


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.

like image 24
EyasSH Avatar answered Nov 09 '22 18:11

EyasSH