Why Destructor Is Not Called on Exception

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.

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().

Destructor not called when an exception is thrown

You are creating an array of 5 Test objects but you throw an exception after you create 3 complete objects, The exception is thrown while in the constructor of the 4th object. The construction of the 4th object is not complete until the closing brace of the constructor is reached.

The stack unwinds calling destructor for those 3 completely constructed objects in the opposite order in which they were created, since the 4th and 5th object were never constructed the destructor for them is never called.

The rule for exception is:

Once an exception is thrown destructors for all completely created objects within that scope will be called.

An completely created object is one whose constructor has been called cleanly without any exceptions.

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.

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.

Why I couldn't handle an exception thrown from a destructor outside of it?

I think you misunderstood the recommendation:

a destructor usually should not throw an exception like STL containers and if it should, that thrown expression should be wrapped in a try-catch block (a catch must handle that exception).

In other words, it says:

You should not throw an exception from a destructor.

Now the question arises what one should do if the destructor is:

~Bar() {  
do_something();
}

and do_something() might throw an exception. In this case the recommendation is to catch the exception and handle it:

~Bar() {
try {
do_something();
} catch(...) {
// handle exception, eg write a log message
// but do not retrow it or a different one!
}
}

Now there is no way the exception leaves the destructor.


As you discovered, catching the exception outside of the destructor does not help to solve the general problem, because here:

 try{
Foo f{};
Foo* pFoo = new Foo{};
delete pFoo; // normally exception caught here nad handled by the following catch
}

The call to delete pFoo; throws an exception. During stack unwinding Foo f{}; will be destroyed and another exception will be thrown from the destructor. If an exception is thrown during stack-unwinding std::terminate will be called. And the way to avoid that to happen is to not throw exceptions from destructors.

Under what circumstances are C++ destructors not going to be called?

Are there any other circumstances where they[destructors] will not be called?

  1. Long jumps: these interfere with the natural stack unwinding process and often lead to undefined behavior in C++.
  2. Premature exits (you already pointed these out, though it's worth noting that throwing while already stack unwinding as a result of an exception being thrown leads to undefined behavior and this is why we should never throw out of dtors)
  3. Throwing from a constructor does not invoke the dtor for a class. This is why, if you allocate multiple memory blocks managed by several different pointers (and not smart pointers) in a ctor, you need to use function-level try blocks or avoid using the initializer list and have a try/catch block in the ctor body (or better yet, just use a smart pointer like scoped_ptr since any member successfully initialized so far in an initializer list will be destroyed even though the class dtor will not be called).
  4. As pointed out, failing to make a dtor virtual when a class is deleted through a base pointer could fail to invoke the subclass dtors (undefined behavior).
  5. Failing to call matching operator delete/delete[] for an operator new/new[] call (undefined behavior - may fail to invoke dtor).
  6. Failing to manually invoke the dtor when using placement new with a custom memory allocator in the deallocate section.
  7. Using functions like memcpy which only copies one memory block to another without invoking copy ctors. mem* functions are deadly in C++ as they bulldoze over the private data of a class, overwrite vtables, etc. The result is typically undefined behavior.
  8. Instantiation of some of smart pointers (auto_ptr) on an incomplete type, see this discussion

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.

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.



Related Topics



Leave a reply



Submit