views:

155

answers:

4

Will the destructor of the base class be called if an object throws an exception in the constructor?

+11  A: 

If an exception is thrown during construction, all previously constructed sub-objects will be properly destroyed. The following program proves that the base is definitely destroyed:

struct Base
{
    ~Base()
    {
        std::cout << "destroying base\n";
    }
};

struct Derived : Base
{
    Derived()
    {
        std::cout << "throwing in derived constructor\n";
        throw "ooops...";
    }
};

int main()
{
    try
    {
        Derived x;
    }
    catch (...)
    {
        throw;
    }
}

output:

throwing in derived constructor
destroying base

(Note that the destructor of a native pointer does nothing, that's why we prefer RAII over raw pointers.)

FredOverflow
I can't remember - if you hadn't caught the exception, is the base class destructor guaranteed to be called, or does that count as part of "stack unwinding" and hence it's implementation-defined whether it occurs or not on an uncaught exception?
Steve Jessop
@Steve: Without the catch, the base is not destroyed on my implementation, so I *guess* it's not guaranteed, but who knows... :-)
FredOverflow
Which is why it is a good idea to put a catch and re-throw in main to force the stack to be unwound correctly.
Martin York
@Martin: Interesting, I have updated my answer accordingly.
FredOverflow
+7  A: 

Yes. The rule is that every object whose constructor has finished successfully will be destructed upon exception. E.g:

class A {
public:
    ~A() {}
};

class B : public A {
public:
    B() { throw 0; }
    ~B() {}
};

~A() is called. ~B() is not called;

EDIT: moreover, suppose you have members:

struct A {
    A(bool t) { if(t) throw 0; }
    ~A() {}
};

struct B {
    A x, y, z;
    B() : x(false), y(true), z(false) {}
};

What happens is: x is constructed, y throws, x is destructed (but neither y nor z).

ybungalobill
+3  A: 

When an exception is thrown, the destructors are called for all (sub-) objects whose constructors were successfully run. This extends to data members and base classes alike.

For example, for this code

struct base {};

struct good {};

struct bad {
  bad() {throw "frxgl!";}
};

struct test : public base {
  std::string s;
  good g;
  bad b;
  test() {}
};

before test's constructor is executed, first the constructor for the base class is called, then the constructors for s, g, and b. Only if these finish successfully, the constructor for test is executed. When the exception is thrown during the construction of b, the base class constructors as well as the constructors for the data members s and g have been fully executed, so their destructors are run. The constructor of test itself and of b have not been run successfully, so their destructors are not run.

sbi
+2  A: 

From Standard docs, 15.3 - 11,

The fully constructed base classes and members of an object shall be destroyed before entering the handler of a function try- block of a constructor or destructor for that object.

liaK
Nice quote, but it does not answer the question.
FredOverflow
@FredOverflow, Yeah thanks... Updated now.. :)
liaK