Will the destructor of the base class be called if an object throws an exception in the constructor?
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.
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.
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).
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.)