I started to learn the subject of exceptions in C++.
I encountered the term "stack unwinding" which means, to my understanding,
that whenever exception is thrown, and there is no catch block inside the "throwing function", the function stack will "unwind", and by this all local object's d'tor will be called (and the same will also happen in the outer functions untill a suitable catch block will be encountered).
My question:
suppose the exception was thrown inside a try block with suitable following catch,
will the d'tor will be called for all objects defined inside the try block?
or to all objects defined in the try block until the exception occured? or to no object at all, and they will "wait" for the function to exit?
The semantics is that any local variable declared in a block should be destroyed when the control leaves the block (a function is a named block with parameters that are local variables). So when you leave a try-block any locally created variable will be destroyed and its appropriate dtor called. Everything that was created is destroyed, if something was not created, it simply cannot be destroyed. The only thing that is not destroyed is the exception objet itself if it is thrown (of course).
From the C++ spec:
15.2 Constructors and destructors 1. As control passes from the point where an exception is thrown 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
15.2 Constructors and destructors 3. The process of calling destructors for automatic objects constructed
on the path from a try block to the point where an exception is thrown
is called “stack unwinding.”
Related
Suppose I am doing something like:
try
{
do_job();
}
catch(...)
{
std::cout << "GUI is running so we won't terminate and raise a clear error here instead" << std::endl;
};
When calling a failing do_job some static variables/classes are initiated, are they "destroyed" after the catch? If not how to handle this please (i.e. memory allocated to statics)?
My generic problem is: I am having a GUI looping to display stuff to the user, say a game, if an error occur, the program will call std::termniate() I guess, or something similar, but I will find myself in the lovely file <abort>, the GUI then is crached, how can I handle this and reset static variables created when do_job is called please? Shoud I just let them initiated? The user in this case might change mind and not even use the static variables that have been created, so they are there with no use taking memory?
Static storage duration variables, if they have been successfully initialized, will always be destroyed at normal program termination, not earlier.
If a static variable wasn't successfully initialized then it will not be destroyed.
In any case there is nothing for you to take care of under normal conditions. In particular when throwing from do_job, either the static has been fully initialized at the point of the throw or it hasn't been. In the former case it will be destroyed at normal program termination, in the latter case it doesn't need to be destroyed.
In the situation of a std::terminate call, it looks different. It is called under abnormal conditions, such as if an exception is uncaught or an exception thrown while stack unwinding is in progress or an exception escapes a noexcept function.
The default std::terminate handler will call std::abort which abnormally terminates the program and explicitly does not destruct any static storage duration objects. The program just abruptly terminates without any chance to execute any further instructions (except maybe for a SIGABRT handler).
The std::terminate handler can be replaced, but the conditions under which std::terminate is called don't really allow for normal program termination and surely not for sensible continuation of program execution.
The best solution is to not let the abnormal conditions causing it to be called happen. Make sure to not let exceptions escape from main, destructors or noexcept functions. (There are more sources of std::terminate calls. All of them should be avoided.)
When calling a failing do_job some static variables/classes are initiated, are they "destroyed" after the catch?
Variables with static storage duration are destroyed after main returns (either normally, or call to std::exit).
stack unwinding
In the stack unwinding section there are the two following paragraphs:-
Once the exception object is constructed, the control flow works backwards (up the call stack) until it reaches the start of a try block, at which point the parameters of all associated catch blocks are compared, in order of appearance, with the type of the exception object to find a match (see try-catch for details on this process). If no match is found, the control flow continues to unwind the stack until the next try block, and so on. If a match is found, the control flow jumps to the matching catch block.
As the control flow moves up the call stack, destructors are invoked for all objects with automatic storage duration that are constructed, but not yet destroyed
Then we have
If an exception is thrown and not caught, including exceptions that escape the initial function of std::thread, the main function, and the constructor or destructor of any static or thread-local objects, then std::terminate is called. It is implementation-defined whether any stack unwinding takes place for uncaught exceptions.
Now I'm a bit confused, at first it says as we move up the stack looking for a try with a matching catch, the destructors are called and then it says if the exception is not caught the destructors are not guaranteed to be called. Which is it? Does the runtime keep track of the destructors that would potentially be called until it finally finds a matching catch and only then it calls them in reverse order of construction? Moreover, are the destructors called before the catch gets executed?
You seem to be under the impression that the destructors are called while searching for a matching catch(). That does not have to be the case.
Destructors from the current location in the program to the matching catch() end up getting called, but that does not need to start happening until the catch is found.
The second block just states that if no catch is found, then the program is allowed to immediately terminate as soon as it makes that determination.
Which is it?
The language itself does not care how an implementation works, only how it behaves. As long as the behavior respects all the requirements, anything is fair game. In this case, it could go either way.
Moreover, are the destructors called before the catch gets executed?
For this part, there is no leeway, they must be executed prior to the code in the catch() statement starting.
I'm writing a drop-replacement for a container, and I'm trying to
get all the exception-guarantees in place. I'm currently writing
the clear method, and I want it to complete as much as possible,
and to always leave the container in a consistent state, even if
one of the destructors throw an exception. I also want to rethrow
the exception after I'm done cleaning, preferably without slicing.
This brings me to the question; when is an exception destructed?
Lets have a look at one attempt:
This is simplified for the example.
void container::clear()
{
bool had_exception = false;
std::exception* exp;
internal_set_empty(); // this cant throw
while( ! internal_done() )
{
try
{
internal_destruct_next(); // this might throw if T::~T() throws
}
catch( std::exception& e )
{
had_exception = true;
exp = &e;
}
}
if( had_exception )
throw *exp;
}
I expect this to fail badly, because the exception is probably destructed
when it is considered handled, and this doesn't technically rethrow.
Another attempt would be taking a copy of the exception, something that
I expect would slice.
Is there a way to extend the lifetime of the exception so I can rethrow
it later?
If possible, I would also like to be able to rethrow exceptions caught
via catch(...) .
even if one of the destructors throw an exception
Cannot be done. Destructors are nothrow for a reason- you can't recover from a throwing destructor. It's clear that you don't do anything to clean up the objects whose destructor threw- because how could you even try to do that- but that also means that you've just left them hanging around in a zombie state.
On your more specific question, you could use recursion to stay inside the catch's stack frame to try to keep deleting elements, or you could also use std::exception_ptr and friends in C++11 which are intended for transporting exceptions around.
The current usage to pass the exception to a caller is to rethrow it in the catch bloc. Assuming you have good reasons not to do it, the only other correct way is to use a std::exception_ptr. With a mere std::exception* there are high risk that the exception is destroyed and its memory deallocated before you can throw it again.
Standard C++ 2011 draft (n4296) says at 15.1 Throwing an exception § 4 : The exception
object is destroyed after either the last remaining active handler for the exception exits by any means other
than rethrowing, or the last object of type std::exception_ptr that refers to the exception object is
destroyed, whichever is later. In the former case, the destruction occurs when the handler exits, immediately
after the destruction of the object declared in the exception-declaration in the handler, if any. In the latter
case, the destruction occurs before the destructor of std::exception_ptr returns. The implementation
may then deallocate the memory for the exception object; any such deallocation is done in an unspecified
way (emphasize mine)
In the following code, I use a wrapper object to temporarily store some stuff from a db in memory. My question is simple:
Can I be sure that the destructor is called? I am particularly worried about cases where
a) testCondition is true and the function returns early from an inner scope of the scope in which tempObj was constructed
b) some runtime error occurs during the execution of this function (which is caught at a higher level)
(As a side question: is this a good way to temporarily store some data? In my application, someFunc() is a save/export function of the current db.)
class TempStore
{
public:
TempStore() {/* delete some stuff from a db and store this in memory*/}
~TempStore() {/* write this stuff back into the db*/}
};
void someFunc(bool testCondition)
{
TempStore tempObj = TempStore();
// some code
if (testCondition)
return; //early return
// some more code
}
The destructor of an automatic object will be called when the program leaves the object's scope. This includes returning from the function (early or otherwise), and leaving via an exception - as long as the exception is handled. In the case of an exception, it's called during stack unwinding before the exception is handled.
It might not be called in some cases, including:
leaving via a call to longjmp; this gives undefined behaviour;
leaving via an exception that's not handled; it's unspecified whether the stack is unwound.
terminating the program (e.g. calling exit, or raising a signal that causes termination).
The destructor will be called unless the program blows up due to a seg fault or a power outage or whatever. Simply returning early from a function or throwing an exception is not enough to stop the destructor running.
This design is a bit flawed though, since writing to a database is an operation that could fail, and throwing an exception from a destructor is a pretty bad idea.
Yes, destructor will be called. Every object, created on stack will be correctly destroyed if you early return. If exception is thrown, destructor will be called after program execution arrived to the catch block.
C++ automagically calls destructors of all local variables in the block in reverse order regardless of whether the block is exited normally (control falls through) or an exception is thrown.
Looks like the term stack unwinding only applies to the latter. How is the former process (the normal exit of the block) called concerning destroying local variables?
An object is automatically destructed when it "goes out of scope". This could be referred to as "automatic storage reclamation", but that actually refers to garbage collection (there are several papers with that phrase in their name that use the term to mean garbage collection). When it is used to ensure proper pairing of open/close, lock/unlock, or other forms of resource acquisition with their appropriate release, then it is known as the design pattern of Resource Acquisition is Initialization (RAII), which is somewhat ironic given that the main aspect of RAII is not the resource initialization or acquisition, but rather its destruction.
Stack unwinding happens in both these cases, it's just that under normal execution the stack is unwound only to the context of the calling method (or block) when the executing method returns (or the block is exited). Local variables are allocated on the stack, so they are cleaned up in reverse order of allocation, and it's this process that is called unwinding. It's no different than processing any other type of data that you'd store in a LIFO structure - e.g. undo, redo.
When an exception is thrown the handler will unwind the stack through through zero or more methods until it finds one that can catch the exception, or until it reaches the top of the stack, at which point the unhandled exception handler will be called.
It seems to be convention to only use the term stack unwinding in the case of exception handling, but it's the same process occurring in each of these cases. The specific case where the stack unwinds due to a method exiting is called returning, there doesn't seem to be any convention for naming what happens when a scoped block of code is exited.
The local variable is destroyed when it goes out of scope. Perhaps the process is called like "going out of scope"?
I'm not sure there is a name for this. Stack variables are so automatic that no one worries about them, ever, not even enough to give a name for this automatic cleanup process.
Call it "going out of scope", I guess.
I've always heard it spoken as "going out of scope" or more precisely "an auto variable going out of scope".
If what you're asking is how the method call is actually implemented in machine code, I would say it would depend on the calling convention used