37

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?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
amit singh
  • 385
  • 1
  • 3
  • 8

2 Answers2

69

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

Community
  • 1
  • 1
Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • Actually `std::terminate` called with unnamed variable as well. According to `iostream.h` OP uses old compiler – Slava Mar 23 '17 at 12:52
  • 1
    @Slava: that's an unrelated issue. In C++11 destructors are implicitly `noexcept`. Will amend my answer. – Vittorio Romeo Mar 23 '17 at 12:54
10

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.

EyasSH
  • 3,679
  • 22
  • 36