What Destructors Are Run When the Constructor Throws an Exception

What destructors are run when the constructor throws an exception?

if a constructor throws an exception, what destructors are run?

Destructors of all the objects completely created in that scope.

Does it make any difference if the exception is during the initialization list or the body?

All completed objects will be destructed.

If constructor was never completely called object was never constructed and hence cannot be destructed.

what about inheritance and members? Presumably all completed constructions get destructed. If only some members are constructed, do only those get destructed? If there is multiple inheritance, do all completed constructors get destructed? Does virtual inheritance change anything?

All completed constructions do get destructed. Yes, only the completely created objects get destructed.

Good Read:

Constructor Failures by Herb Sutter

Especially, love the part where he explains:

In biological terms, conception took place -- the constructor began --, but despite best efforts it was followed by a miscarriage -- the constructor never ran to term(ination).

Incidentally, this is why a destructor will never be called if the constructor didn't succeed -- there's nothing to destroy. "It cannot die, for it never lived." Note that this makes the phrase "an object whose constructor threw an exception" really an oxymoron. Such a thing is even less than an ex-object... it never lived, never was, never breathed its first.

Is the destructor called if the constructor throws an exception?

Preamble: Herb Sutter has a great article on the subject:

http://herbsutter.wordpress.com/2008/07/25/constructor-exceptions-in-c-c-and-java/

C++ : Yes and No

While an object destructor won't be called if its constructor throws (the object "never existed"), the destructors of its internal objects could be called.

As a summary, every internal parts of the object (i.e. member objects) will have their destructors called in the reverse order of their construction. Every thing built inside the constructor won't have its destructor called unless RAII is used in some way.

For example:

struct Class
{
Class() ;
~Class() ;

Thing * m_pThing ;
Object m_aObject ;
Gizmo * m_pGizmo ;
Data m_aData ;
}

Class::Class()
{
this->m_pThing = new Thing() ;
this->m_pGizmo = new Gizmo() ;
}

The order of creation will be:

  1. m_aObject will have its constructor called.
  2. m_aData will have its constructor called.
  3. Class constructor is called
  4. Inside Class constructor, m_pThing will have its new and then constructor called.
  5. Inside Class constructor, m_pGizmo will have its new and then constructor called.

Let's say we are using the following code:

Class pClass = new Class() ;

Some possible cases:

  • Should m_aData throw at construction, m_aObject will have its destructor called. Then, the memory allocated by "new Class" is deallocated.

  • Should m_pThing throw at new Thing (out of memory), m_aData, and then m_aObject will have their destructors called. Then, the memory allocated by new Class is deallocated.

  • Should m_pThing throw at construction, the memory allocated by "new Thing" will be deallocated. Then m_aData, and then m_aObject will have their destructors called. Then, the memory allocated by new Class is deallocated.

  • Should m_pGizmo throw at construction, the memory allocated by "new Gizmo" will be deallocated. Then m_aData, and then m_aObject will have their destructors called. Then, the memory allocated by new Class is deallocated. Note that m_pThing leaked

If you want to offer the Basic Exception Guarantee, you must not leak, even in the constructor. Thus, you'll have to write this this way (using STL, or even Boost):

struct Class
{
Class() ;
~Class() ;

std::auto_ptr<Thing> m_pThing ;
Object m_aObject ;
std::auto_ptr<Gizmo> m_pGizmo ;
Data m_aData ;
}

Class::Class()
: m_pThing(new Thing())
, m_pGizmo(new Gizmo())
{
}

Or even:

Class::Class()
{
this->m_pThing.reset(new Thing()) ;
this->m_pGizmo.reset(new Gizmo()) ;
}

if you want/need to create those objects inside the constructor.

This way, no matter where the constructor throws, nothing will be leaked.

Destructor not invoked when an exception is thrown in the constructor

A C++ object's lifetime begins only after its constructor completes successfully.

Since the exception was thrown before constructor call was complete you don't have an complete object and hence no destructor.

Herb Sutter explains this nicely, to quote him:

Q: What does emitting an exception from a constructor mean?

A: It means that construction has failed, the object never existed, its lifetime never began. Indeed, the only way to report the failure of construction -- that is, the inability to correctly build a functioning object of the given type -- is to throw an exception. (Yes, there is a now-obsolete programming convention that said, "if you get into trouble just set a status flag to 'bad' and let the caller check it via an IsOK() function." I'll comment on that presently.)

In biological terms,

conception took place -- the constructor began -- but despite best efforts it was followed by a miscarriage -- the constructor never ran to term(ination).

Incidentally, this is why a destructor will never be called if the constructor didn't succeed -- there's nothing to destroy. "It cannot die, for it never lived." Note that this makes the phrase "an object whose constructor threw an exception" really an oxymoron. Such a thing is even less than an ex-object... it never lived, never was, never breathed its first. It is a non-object.

We might summarize the C++ constructor model as follows:

Either:

(a) The constructor returns normally by reaching its end or a return statement, and the object exists.

Or:

(b) The constructor exits by emitting an exception, and the object not only does not now exist, but never existed as an object.

EDIT 1:
But if the exception happens in the main(), ie after the MyClass object is fully instantiated, will the MyClass destructor be invoked?

Yes, it will be!

That is the purpose of using scoped_ptr, Once an exception is thrown in main, Stack Unwinding would cause all local objects to be deallocated, this means that myinst(which resides on stack) will also be deallocated, which in turn will call the destructor of MyClass.

Refer the Boost doccumentation when in doubt:

The scoped_ptr class template stores a pointer to a dynamically allocated object. (Dynamically allocated objects are allocated with the C++ new expression.) The object pointed to is guaranteed to be deleted, either on destruction of the scoped_ptr, or via an explicit reset

EDIT 2:
Why does your edited program crash?
Your program shows crashes because, You throw an exception but you never catch it. when such a scenario occurs an special function called terminate() is called whose default behavior is to call abort().It is implementation defined behavior whether stack is Unwound before terminate() is called in this particular scenarioRef 1.Seems your implementation doesn't & you should not rely on this behavior as well.

You can modify your program as follows to handle the exception and you should get the behavior you were expecting:

#include <boost/scoped_ptr.hpp> 
#include <iostream>

class MyClass {
boost::scoped_ptr<int> ptr;
public:
MyClass() : ptr(new int) { *ptr = 0; std::cout<<"MyClass Allocated\n"; }
~MyClass() { std::cout<<"MyClass De-allocated\n"; }
int increment() { return ++*ptr; }
};

void doSomething()
{
boost::scoped_ptr<MyClass> myinst(new MyClass);
throw 3;
}

int main()
{
try
{
doSomething();
}
catch(int &obj)
{
std::cout<<"Exception Handled";
}

}

Ref1C++03 15.5.1 The terminate() function

In the following situations exception handling must be abandoned for less subtle error handling techniques:

....

— when the exception handling mechanism cannot find a handler for a thrown exception (15.3),

....

In such cases,


  1. void terminate();

is called (18.6.3). In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before terminate() is called. In all other situations, the stack shall not be unwound before terminate() is called. An implementation is not permitted to finish stack unwinding prematurely based on a determination that the unwind process will eventually cause a call to terminate().

Exception thrown in a constructor: is the destructor called?

The destructor will not be called because the foo object is not considered fully constructed until a constructor has finished executing (note that this means if you throw in a constructor that delegated to a different constructor then the destructor will be called). Throwing from a constructor is not undefined behaviour.

What happens if a constructor throws an exception?

No, throwing an exception is the best way to signal an error during object construction. (Since there's no return value, there's no other way, other than constructing a headless object, which is bad style in C++.)

From the man himself, Bjarne Stroustrup: http://www.stroustrup.com/bs_faq2.html#ctor-exceptions

(If you are working in a project where exceptions aren't allowed, then you have to make the constructor infallible, and move any logic that could fail into a factory function that has the possibility of returning an error.)

Re: "But my destructor was not called"

Indeed.
In C++ the lifetime of an object is said to begin when the constructor runs to completion. And it ends right when the destructor is called. If the ctor throws, then the dtor is not called.

(But dtors of any member variable objects, whose ctors already ran to completion before this ctor ran, are called.)

You should consult the standard, or a good textbook for more details, esp. related to what happens when inheritance is involved. As a general rule of thumb, destructors are called in the reverse order of construction.

Your question about why "~B" was not called in your specific code, it's because you do not catch the exception in main. If you change your code so that main catches the exception, then "~B()" will be called. But, when an exception is thrown which has no catch, the implementation is free to terminate the program without calling destructors or destroying statically initialized objects.

Reference in C++11 standard (emphasis mine):

15.5.1 The std::terminate() function [except.terminate]

1
In some situations exception handling must be abandoned for less subtle error handling techniques.

...

2
In such cases, std::terminate() is called (18.8.3). In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before std::terminate() is called.

As a side note, generally speaking with gcc and clang, ~B will be called anyways in your example program, while with MSVC, ~B will not be called. Exception handling is complex and the standard allows that compiler writers can experiment with and choose what implementation that they think is best in this regard, but they cannot choose to give undefined behavior.

If it's really important for your program that the destructors are called even in this case, then you should make sure to catch exceptions in main so that your code will be portable (work the same on all conforming compilers). For example:

int main() {
try {
A a;
} catch (...) {}
}

This way, compilers like MSVC will be obligated to call the destructor of B before exiting.

Are destructors called after a throw in C++?

Yes, it is guaranteed (provided the exception is caught), down to the order in which the destructors are invoked:

C++11 15.2 Constructors and destructors [except.ctor]

1 As control passes from a throw-expression to a handler, destructors are invoked for all
automatic objects constructed since the try block was entered. The
automatic objects are destroyed in the reverse order of the completion
of their construction.

Furthermore, if the exception is thrown during object construction, the subobjects of the partially-constructed object are guaranteed to be correctly destroyed:

2 An object of any storage duration whose initialization or
destruction is terminated by an exception will have destructors
executed for all of its fully constructed subobjects (excluding the
variant members of a union-like class), that is, for subobjects for
which the principal constructor (12.6.2) has completed execution and
the destructor has not yet begun execution. Similarly, if the
non-delegating constructor for an object has completed execution and a
delegating constructor for that object exits with an exception, the
object’s destructor will be invoked. If the object was allocated in a
new-expression, the matching deallocation function (3.7.4.2, 5.3.4,
12.5), if any, is called to free the storage occupied by the object.

This whole process is known as "stack unwinding":

3 The process of calling destructors for automatic objects constructed
on the path from a try block to a throw-expression is called “stack
unwinding.” If a destructor called during stack unwinding exits with
an exception, std::terminate is called (15.5.1).

Stack unwinding forms the basis of the widely-used technique called Resource Acquisition Is Initialization (RAII).

Note that stack unwinding is not necessarily done if the exception is not caught. In this case it's up to the implementation whether stack unwinding is done. But whether stack unwinding is done or not, in this case you're guaranteed a final call to std::terminate.

C++11 15.5.1 The std::terminate() function [except.terminate]

2 … In the situation where no matching handler is found,
it is implementation-defined whether or not the stack is unwound before std::terminate() is called.

Destroying the member variables of an object when an exception is thrown in its constructor in C++

The destructor of AnimalLoverProfile is never called because this object is not constructed yet, while the destructor for theName will be called because this object is properly constructed (even though it is a field of an object that has not been completely constructed yet). It is possible to avoid any memory leaks here by using smart pointers:

::std::unique_ptr<Image> profilePicture;
::std::unique_ptr<Image> pictureOfPet;

In this case, when new Image(pictureOfPetFileName) throws, the profilePicture object will have already been constructed, which means that its destructor will be called, just as the destructor of theName is called.

How does RAII work when a constructor throws an exception?

You're misunderstanding the first quote. That's not hard, since it's confusing.

if a member object with RAII semantics has been created and an exception happens before the constructor has completed then its destructor will be called as part of the stack unwinding.

That's what it says. Here's what it meant:

if a member object with RAII semantics has been created and an exception happens in the outer object before the outer object's constructor has completed then the member object's destructor will be called as part of the stack unwinding.

See the difference? The idea is that the member object completed its constructor, but the owning type didn't. It threw somewhere in its constructor (or a constructor of another member that is initialized after that one). This will cause the destructor of all of its members to be called (all of the ones that completed construction, that is), but not its own destructor.

Here's an example:

class SomeType
{
InnerType val;
public:
SomeType() : val(...)
{
throw Exception;
}
};

When you create a SomeType instance, it will call InnerType::InnerType. As long as that doesn't throw, it will then enter SomeType's constructor. When that throws, it will cause val to be destroyed, thus calling InnerType::~InnerType.

Destructor called after throwing from a constructor

Delegating constuctors are indeed a new feature that introduces a new destruction logic.

Let us revisit the lifetime of an object: An object's lifetime begins when some constructor has finished. (See 15.2/2. The standard calls this the "principal constructor".) In your case, this is the constructor X(int). The second, delegating constructor X() acts as just a plain member function now. Upon scope unwinding, the destructors of all fully-constructed objects are called, and this includes x.

The implications of this are actually quite profound: You can now put "complex" work loads into a constructor and take full advantage of the usual exception propagation, as long as you make your constructor delegate to another constructor. Such a design can obviate the need for various "init"-functions that used to be popular whenever it wasn't desired to put too much work into a regular constructor.

The specific language that defines the behaviour you're seeing is:

[C++11: 15.2/2]: [..] Similarly, if the non-delegating constructor for an object
has completed execution and a delegating constructor for that object exits with an exception, the object’s destructor will be invoked. [..]



Related Topics



Leave a reply



Submit