Reputation: 2830
Looking on the internet for C++ brainteasers, I found this example:
#include <iostream>
using namespace std;
class A {
public:
A()
{
cout << "A::A()" << endl;
}
~A()
{
cout << "A::~A()" << endl;
throw "A::exception";
}
};
class B {
public:
B()
{
cout << "B::B()" << endl;
throw "B::exception"; // <- crashes here
}
~B()
{
cout << "B::~B()";
}
};
int main(int, char**) {
try
{
cout << "Entering try...catch block" << endl;
A objectA;
B objectB;
cout << "Exiting try...catch block" << endl;
}
catch (const char* ex)
{
cout << ex << endl;
}
return 0;
}
This is what I thought the program would do:
However, when I ran the program, it actually crashed at the line marked with <-. Could anybody explain what exactly was going on at that point?
Upvotes: 0
Views: 428
Reputation: 7694
Your should NEVER throw an exception in destructor. Take a look at this question why.
Upvotes: 2
Reputation: 170479
When B::B()
throws an exception stack unwinding begins. A::~A()
is called and throws another exception that is not catched inside A::~A()
.
If another exception leaves a destructor while stack unwinding is in progress terminate() is called and that looks like a program crash.
Upvotes: 6
Reputation: 12403
If you are really coding, not just brainteasing never ever throw exception from destructor. If an exception is thrown during stack-unwinding, terminate()
is called. In your case destructor of A has thrown while processing exception that was thrown in B's constructor.
EDIT:
To be more precise (as suggested in comments) - never ever let exception escape destructor. Exceptions that are caught inside destructor make no problem. But if during stack unwinding program has to deal with two exceptions - the one that caused stack unwinding and the one that escaped destructor during unwinding, std::terminate()
goes.
Upvotes: 11
Reputation: 8869
The code crashes because B's C'tor throws an exception, and then starts the "Stack Unwinding" procedure: all the local objects are destructed, dus, A's D'tor is called, and throws an exception during the Stack unwinding, and then "abort" is called, because there can't be two exceptions at the same time...
Conclusion:
Never throw an exception from a D'tor, because you might be throwing it during Stack Unwinding.
Upvotes: 3
Reputation: 47042
A::~A()
is called when the try block is exited, precisely because the object goes out of scope. This is why RAII works --- it depends on destructors being called regardless of why the scope is exited.
A::~A()
then throws an exception. As B::B()
's exception is still being thrown up the stack, this crashes the program.
Upvotes: 2
Reputation:
Golden rule in C++ - destructors should never throw exceptions. Ignoring this rule will lead to undefined behaviour in all sorts of situations.
Upvotes: 4