amit singh
amit singh

Reputation: 395

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

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>

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

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?

Upvotes: 38

Views: 13728

Answers (2)

Vittorio Romeo
Vittorio Romeo

Reputation: 93254

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:


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

Upvotes: 70

EyasSH
EyasSH

Reputation: 3769

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.

Upvotes: 10

Related Questions