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"); }
}
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.
I have a class CustomException, that implements std::exception, in which I explicitely deleted the copy and move constructors. When I throw an exception of that class, there are compiling errors for calling the deleted constructors.
Are CustomException instances being created somewhere? What objects are created when the exception is thrown?
When you throw, an exception object is constructed that has the same type as the operand of throw with top-level cv-qualifiers removed (if you throw an array or function, they also decay to their corresponding pointers).
So what you did is a no-go, I'm afraid.
C++ standard chapter [except.throw] §5:
When the thrown object is a class object, the copy/move constructor and the destructor shall be accessible, even if the copy/move operation is elided (12.8).
Before unwinding stack a throw operator (except throw; without an argument, used for rethrowing) creates an exception object in a special memory area. Depending on circumstances, the object is initialized in different ways: constructor, copy constructor, move constructor (https://en.cppreference.com/w/cpp/language/copy_elision) using what was provided to the throw operator. So the information is available from the exception object, which is alive until completing handling the exception, though what was provided to the throw operator is destroyed when the stack is unwound).
In your case the compiler needs the functions you deleted to either initialize the exception object when throwing the exception or to initialize the catch-clause argument, or both - since it is how the compiler does it by design (using the functions).
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.
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.
Let's say I have class that acts as a "smart pointer" and releases some kind of system resource when destroyed.
class Resource{
protected:
ResourceHandle h;
public:
Resource(ResourceHandle handle)
:h(handle){
}
~Resource(){
if (h)
releaseResourceHandle(h);//external function, probably from OS
}
};
And I have some function that returns value used for initialization of "Resource":
ResourceHandle allocateHandle();
Now, if I do this in my code:
Resource resource(allocateHandle());
AND allocateHandle() throws an exception, what exactly will happen? Will the crash occur during construction of Resource() or before the construction?
Common sense tells me that because exception is thrown before allocateHandle returns, execution won't even enter Resource() constructor, but I'm not exactly sure about it. Is this a correct assumption?
Arguments are evaluated before any function call -- in this case the constructor --.
Therefore, the exception is thrown before the constructor call
Yes you are correct (as everybody else has said).
But what you are alluding to (I think).
What happens to the object if the constructor was entered and the exception is thrown.
Would the destructor still get executed or not?
Destructors are only fired if the constructor actually finished (if an exception is throw that escapes the constructor then the constructor is not finished). In this case the constructor is not entered and thus the object does not exist and therefore the destructor will not be executed.
What happens if the exception is thrown while the constructor is executing.
In this case because the constructor was not completed the destructor will never be executed either, but what about all the member fields? If the constructor is left via an exception then all fully formed members will have their destructors called (A fully formed member is a member whose constructor has been called and completed successfully).
This is a correct assumption.
If the compiler entered the constructor, what value could it pass in from a function that didn't return?
Yes, your assumption is correct.
At this point you are only creating your parameters and pushing them on the stack. The Object of "Resource" is not even formed!
Therefore, an exception will not call the destructor during stack unwinding.