Are Destructors Called After a Throw in C++

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.

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.

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 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. [..]

Why aren't destructors called when an uncaught exception is throw in C++ during array creation?

When you don't catch an exception (i.e. it becomes an uncaught exception and terminates your program), C++ doesn't give you any guarantees that destructors actually get called.

This gives the compilers leeway in how to implement exception handling. For example, GCC first searches for a handler. If it can't find one, it aborts immediately, preserving the full stack information for debugging. If it does find one, it actually unwinds the stack, destroying objects, until it arrives at the handler. That's why you don't see output: the program aborts before destroying any objects.

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.

Why destructor is not called on exception?

The destructor is not being called because terminate() for the unhandled exception is called before the stack gets unwound.

The specific details of what the C++ spec says is outside of my knowledge, but a debug trace with gdb and g++ seems to bear this out.

According to the draft standard section 15.3 bullet 9:


9 If no matching handler is found in a program, the function terminate()
(_except.terminate_) is called. Whether or not the stack is unwound
before calling terminate() is implementation-defined.

C++: If an exception is thrown, are objects that go out of scope destroyed?

Yes.

C++ Standard n3337

15 Exception handling

§ 15.2 Constructors and destructors

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.

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.

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).
[ Note: So destructors should generally catch exceptions and not let
them propagate out of the destructor. — end note ]

example:

SomeClass c;              // declared before try{} so it is
// still valid in catch{} block
try {
SomeClass t;
throw;
} catch( ...) {
// t destroyed
// c valid
}

Destructor that calls a function that can throw exception in C++

Yes, that's legal. An exception must not escape from the destructor, but whatever happens inside the destructor, or in functions it calls, is up to you.

(Technically, an exception can escape from a destructor call as well. If that happens during stack unwinding because another exception was thrown, std::terminate is called. So it is well-defined by the standard, but it's a really bad idea.)

c++ exception in destructor

The recommendation that "we should not throw exception in destructor" is not an absolute. The issue is that when an exception is thrown the compiler starts unwinding the stack until it finds a handler for that exception. Unwinding the stack means calling destructors for objects that are going away because their stack frame is going away. And the thing that this recommendation is about occurs if one of those destructors throws an exception that isn't handled within the destructor itself. If that happens, the program calls std::terminate(), and some folks think that the risk of that happening is so severe that they have to write coding guidelines to prevent it.

In your code this isn't a problem. The destructor for B throws an exception; as a result, the destructor for a is also called. That destructor throws an exception, but handles the exception inside the destructor. So there's no problem.

If you change your code to remove the try ... catch block in the destructor of A, then the exception thrown in the destructor isn't handled within the destructor, so you end up with a call to std::terminate().

EDIT: as Brian points out in his answer, this rule changed in C++11: destructors are implicitly noexcept, so your code should call terminate when the the B object is destroyed. Marking the destructor as noexcept(false) "fixes" this.



Related Topics



Leave a reply



Submit