This question already has answers here:
Are destructors called after a throw in C++?
(3 answers)
Closed 9 years ago.
I have a code such as this:
class myclass
{
myclass()
{
// doing some init here
}
~myclass()
{
// doing some important clean up here
}
void Do()
{
// doing some work which may throw exception
}
}
and I am using this class in this way:
MyFunction()
{
myclass mc;
mc.do();
}
My question is :
If there is an exception in do function, what would happen? Is destructor of myclass called?
If no, what is the best way to handle this type of situations? Assume that I don't have the source code and I am sure about what is happening in destructor.
If there is an exception in do function, what would happen?
If you have any handler, it will be handled.
Is destructor of myclass called?
Yes, definitely. The standard quotes this::
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":
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).
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.
If the exception is caught somewhere, then stack unwinding will guarantee that the destructor is called for this object (and, in general, all automatic variables that go out of scope as a result of the exception). This is a very important guarantee, without which we could not use techniques like RAII to write exception-safe code.
If the exception is not caught, then the program will be terminated, and it's implementation-dependent whether or not the stack will be unwound first. If it's important to destroy the object cleanly even in that situation, then one option is to catch and rethrow the exception, outside the object's scope.
If the program is ended in some other way, e.g. by calling exit() or terminate(), or receiving an unhandled signal, then the stack won't be unwound. If you need clean destruction in these situations, then things will get messy.
C++ does not have explicit "finally" clauses like many other languages, but instead you rely in "RAII" which essentially is a technique of using scoped "automatic" variables and relying on the fact that their destructor will get called at the appropriate moment when they go out of scope.
In your case the destructor of myclass will be called even if mc.do() throws an exception. In a lot of these "closure" issues, the object you put at the top of the scope block is a class that is used only for the purpose of invoking the destructor on termination.
The "D" language comes with a special closure syntax. There have been attempts to write libraries that do that in C++ and with lambdas it is certainly easier to write than now than it used to be although I do not think they are a formal part of C++ as yet.
Related
This question already has answers here:
If you shouldn't throw exceptions in a destructor, how do you handle errors in it?
(17 answers)
Closed 8 years ago.
It seems you cannot throw exceptions from destructors in case more than one exception is thrown from the destructor.
In Effective C++ Scott Meyers uses a vector example where the first element throws an exception during destruction and then later a second element throws- causing problems for C++ (which cannot handle more than one exception).
Surely this scenario (vectors manipulating elements and elements throwing exceptions) could also happen during a copy constructors implementing deep copying though?
EDIT:
Are we saying that its the recursive-nature of dtors calling underlying dtors which is different to the copy constructor?
Exceptions shouldn't be thrown from destructors because when you throw an exception, the compiler will clean the variables in scope, thus calling their destructors. You'd be in a bad shape if those threw exceptions too.
What is different between constructors and destructors (with regard to throwing) is that
Firstly, destruction of objects is tied to unwinding, and unwinding happens when exceptions are thrown. Unwinding is not tied to construction of objects. That is to say, there is a relationship between destructors and exceptions already.
When some code is interrupted during the construction of an object, this can be safely handled. Resources can be rolled back as if the creation of the object had never been requested. Furthermore, it doesn't matter that subsequent code doesn't run, like the construction of other objects. In the case of destruction, it is essential that it be done properly, otherwise resources leak. It is not okay to abandon a destructor, because that is the last chance for cleaning up an object. Moreover, if the destructor is part of a chain of multiple calls, it is not okay for the remaining destructors to never be called. Neglect to execute destructors will lead to some permanent problem in the program.
Suppose you have a situation like this:
{
A a;
B b;
C c;
// ...
}
Suppose that the statments in the block throw, so the destructors for A, B and C are carried out in reverse order: C::~C then ~B::B and A::~A. Suppose that C::~C throws. This means that not only will the destruction of c be incomplete, but that the destruction of B and A will not happen. The clean-up code for this statement block is simply abandoned.
What should the semantics be?
If none of the destructors can be abandoned in this situation, that means that C::~C has to re-execute if it throws. But that will likely trigger an infinite loop.
Or, unwinding could still do the remaining destructors for b and a. But that still means that the C destructor was abandoned and C is not properly destroyed.
Hi I found this line in a tutorial on web.
What happens when you declare a static object and the destructor throws and exception?
As with static constructor exceptions the application will crash.
I can't seam to understand what's the difference if object is static or not...
Thanks
I'm not sure if you're asking about constructors or destructors that throw exceptions - the problem statement refers to destructors, but the example code and some of the comments refer to constructors.
With regards to constructors that throw, it depends on whether the static object is local or global. Local static objects are constructed the first time that control passes through the scope in which they are defined, and exception handlers should behave normally for them. Global static objects are constructed before the program enters main(); since you can't have a try-catch block at global scope, if the constructor of a global static object throws, it basically means that your application crashes before it makes it out of the starting gate.
As for destructors, generally speaking, destructors that can throw exceptions create serious problems. Herb Sutter details the reasons why in his great book "Exceptional C++", which is available here on Google Books. Basically, if a destructor can throw exceptions, it makes it nearly impossible to write exception-safe code. Consider the following example.
class T
{
T() {}
~T() { throw 5; }
};
void foo()
{
T t;
throw 10;
}
When foo() reaches the throw 10; statement, control will exit the context of foo(), destroying the local object t in the process. This calls the destructor for t, which tries to throw another exception. In C++, it isn't possible to throw two exceptions simultaneously; if a second exception is thrown like this, the program calls the built-in function terminate(), which does what it sounds like and terminates the program (you can set your own function to be called instead using set_terminate, but this is mostly for doing custom clean-up - you can't change the fact that the program ends after the function is done).
The way to avoid this is to make sure that destructors never throw exceptions. It may not matter with static objects, because as celtschk noted the destructor won't be called until the program is terminating anyway, but as a general rule, if you find yourself writing a class with a destructor that can throw an exception, you should think carefully about whether it is really the best approach.
void MyClass::method()
{
SomeObject a;
methodThatCanThrowException();
}
I wish to catch exceptions higher up the call-stack, not in method() - but in this example will the SomeObject destructor be called or not?
Yes. That's why RAII works. It's why exceptions work. They wouldn't otherwise.
Full standard quote:
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.
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 ]
Yes. It's sometimes called stack unwinding
Catching exceptions higher up the stack is often a good idea. I've seen lots of code that catches exception when it can't do much about it.
Just make sure SomeObject's destructor doesn't throw an exception.
I ran a sample program and indeed destructors for stack-allocated objects are called, but is this guaranteed by the standard?
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.
Yes, destructors are guaranteed to be called on stack unwinding, including unwinding due to exception being thrown. There are only few tricks with exceptions that you have to remember:
Destructor of the class is not called if exception is thrown in its constructor.
Exception is automatically re-thrown if caught in construction initialization list catch block.
If a throw is caught then normally cpp operations continue. This include destructors and stack popping. However if the exception is not caught, stack popping is not guaranteed.
Also a bare throw or empty throw cannot be caught by my mobile compiler.
example:
#include <Jav/report.h>
int main()
{
try { throw; }
catch(...) { rep("I bet this is not caught"); }
}
I know that my destructors are called on normal unwind of stack and when exceptions are thrown, but not when exit() is called.
Are there any other cases where my destructors are not going to get called? What about signals such as SIGINT or SIGSEGV? I presume that for SIGSEGV, they are not called, but for SIGNINT they are, how do I know which signals will unwind the stack?
Are there any other circumstances where they will not be called?
Are there any other circumstances where they[destructors] will not be called?
Long jumps: these interfere with the natural stack unwinding process and often lead to undefined behavior in C++.
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)
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).
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).
Failing to call matching operator delete/delete[] for an operator new/new[] call (undefined behavior - may fail to invoke dtor).
Failing to manually invoke the dtor when using placement new with a custom memory allocator in the deallocate section.
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.
Instantiation of some of smart pointers (auto_ptr) on an incomplete type, see this discussion
The C++ standard says nothing about how specific signals must be handled - many implementations may not support SIGINT, etc. Destructors will not be called if exit() or abort() or terminate() are called.
Edit: I've just had a quick search through the C++ Standard and I can't find anything that specifies how signals interact with object lifetimes - perhaps someone with better standards-fu than me could find something?
Further edit: While answering another question, I found this in the Standard:
On exit from a scope (however
accomplished), destructors (12.4) are
called for all constructed objects
with automatic storage duration
(3.7.2) (named objects or temporaries)
that are declared in that scope, in
the reverse order of their
declaration.
So it seems that destructors must be called on receipt of a signal.
Another case they won't be called is if you are using polymorphism and have not made your base destructors virtual.
A signal by itself won't affect the execution of the current thread and hence the invocation of destructors, because it is a different execution context with its own stack, where your objects do not exist. It's like an interrupt: it is handled somewhere outside of your execution context, and, if handled, the control is returned to your program.
Same as with multithreading, C++ the language does not know a notion of signals. These two are completely orthogonal to each other and are specified by two unrelated standards. How they interact is up to the implementation, as long as it does not break either of the standards.
As a side note, another case is when object's destructor won't be called is when its constructor throws an exception. Members' destructors will still be called, though.
abort terminates program without executing destructors for objects of automatic or static storage duration as Standard says. For other situations you should read implementation specific documents.
If a function or method has a throws specification, and throws something NOT covered by the specification, the default behavior is to exit immediately. The stack is not unwound and destructors are not called.
POSIX signals are an operating system specific construct and have no notion of C++ object scope. Generally you can't do anything with a signal except maybe, trap it, set a global flag variable, and then handle it later on in your C++ code after the signal handler exits.
Recent versions of GCC allow you to throw an exception from within synchronous signal handlers, which does result in the expected unwinding and destruction process. This is very operating system and compiler specific, though
A lot of answers here but still incomplete!
I found another case where destructors are not executed. This happens always when the exception is catched across a library boundary.
See more details here:
Destructors not executed (no stack unwinding) when exception is thrown
There are basically two situations, where destructors are called: On stack unwind at the end of function (or at exceptions), if someone (or a reference counter) calls delete.
One special situation is to be found in static objects - they are destructed at the end of the program via at_exit, but this is still the 2nd situation.
Which signal leaves at_exit going through may depend, kill -9 will kill the process immediately, other signals will tell it to exit but how exactly is dependent on the signal callback.