Andy
Andy

Reputation: 2830

Why does the code crash?

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:

  1. A::A() will be output to screen when the constructor of objectA is called. Object A is constructed successfully.
  2. B::B() will be output to screen when the constructor of objectB is called.
  3. The constructor of B then throws an exception. Object B is not constructed successfully.
  4. Destructor of objectB is not called as the constructor never completed successfully.
  5. Destructor of objectA will be called as the object goes out of scope when the try block is exited.

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

Answers (6)

Serge
Serge

Reputation: 7694

Your should NEVER throw an exception in destructor. Take a look at this question why.

Upvotes: 2

sharptooth
sharptooth

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

Tadeusz Kopec for Ukraine
Tadeusz Kopec for Ukraine

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

Gal Goldman
Gal Goldman

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

dave4420
dave4420

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

anon
anon

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

Related Questions