Will exit() or an exception prevent an end-of-scope destructor from being called?
If you call exit
, the destructor will not be called.
From the C++ standard (§3.6.1/4):
Calling the function
void exit(int);
declared in
<cstdlib>
(18.3) terminates the program without leaving the current block and hence without destroying any objects with automatic storage duration (12.4). If exit is called to end a program during the destruction of an object with static storage duration, the program has undefined behavior.
Are destructors run when calling exit()?
No, most destructors are not run on exit()
.
C++98 §18.3/8 discusses this.
Essentially, when exit
is called static objects are destroyed, atexit
handlers are executed, open C streams are flushed and closed, and files created by tmpfile
are removed. Local automatic objects are not destroyed. I.e., no stack unwinding.
Calling abort
lets even less happen: no cleanup whatsoever.
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
}
Under what circumstances are C++ destructors not going to 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
Is a destructor called when an object goes out of scope?
Yes, automatic variables will be destroyed at the end of the enclosing code block. But keep reading.
Your question title asks if a destructor will be called when the variable goes out of scope. Presumably what you meant to ask was:
will Foo's destructor be called at the end of main()?
Given the code you provided, the answer to that question is no since the Foo object has dynamic storage duration, as we shall see shortly.
Note here what the automatic variable is:
Foo* leedle = new Foo();
Here, leedle
is the automatic variable that will be destroyed. leedle
is just a pointer. The thing that leedle
points to does not have automatic storage duration, and will not be destroyed. So, if you do this:
void DoIt()
{
Foo* leedle = new leedle;
}
You leak the memory allocated by new leedle
.
You must delete
anything that has been allocated with new
:
void DoIt()
{
Foo* leedle = new leedle;
delete leedle;
}
This is made much simpler and more robust by using smart pointers. In C++03:
void DoIt()
{
std::auto_ptr <Foo> leedle (new Foo);
}
Or in C++11:
void DoIt()
{
std::unique_ptr <Foo> leedle = std::make_unique <Foo> ();
}
Smart pointers are used as automatic variables, as above, and when they go out of scope and are destroyed, they automatically (in the destructor) delete
the object being pointed to. So in both cases above, there is no memory leak.
Let's try to clear up a bit of language here. In C++, variables have a storage duration. In C++03, there are 3 storage durations:
1: automatic: A variable with automatic storage duration will be destroyed at the end of the enclosing code block.
Consider:
void Foo()
{
bool b = true;
{
int n = 42;
} // LINE 1
double d = 3.14;
} // LINE 2
In this example, all variables have automatic storage duration. Both b
and d
will be destroyed at LINE 2. n
will be destroyed at LINE 1.
2: static: A variable with static storage duration will be allocated before the program begins, and destroyed when the program ends.
3: dynamic: A variable with dynamic storage duration will be allocated when you allocate it using dynamic memory allocation functions (eg, new
) and will be destroyed when you destroy it using dynamic memory allocation functions (eg, delete
).
In my original example above:
void DoIt()
{
Foo* leedle = new leedle;
}
leedle
is a variable with automatic storage duration and will be destroyed at the end brace. The thing that leedle
points to has dynamic storage duration and is not destroyed in the code above. You must call delete
to deallocate it.
C++11 also adds a fourth storage duration:
4: thread: Variables with thread storage duration are allocated when the thread begins and deallocated when the thread ends.
Destructor not being called when leaving scope
If you allocate a object using new
obj2= new cl1;
Then unless you call delete
on it, its destructor won't be called implicitly.
EDIT: As @David, meantions in comments, One may call destructor of an object explicitly but in my experience there is rarely a need to manually call the destructor unless one is using placement new version of new.
Variables on stack are implicitly cleaned up(by calling their destructors) when their scope ends.
Dynamically allocated objects are not implicitly cleaned, it is the responsibility of the user to clean them up explicitly calling delete
.
This is the very reason one should not use raw pointers but use smart pointers.
Is a C++ destructor guaranteed not to be called until the end of the block?
You are OK with this - it's a very commonly used pattern in C++ programming. From the C++ Standard section 12.4/10, referring to when a destructor is called:
for a constructed object with
automatic storage duration
when the block in which the object is
created exits
When do destructors get called when multiple exceptions handlings are involved?
When you catch an exception, the stack is "unwound" between the point where the exception was thrown, and the point where it is caught. This means that all automatic variables in the scopes between those two points are destroyed -- everything inside the try
that corresponds to whatever catch
matches the exception.
Your object obj
is an automatic variable in the main
function, outside the try
. Hence, it is not destroyed when the stack is unwound. Your code relies on that fact -- after the first catch
you call doDivide
on it again, so it better not have been destroyed.
If you don't catch the exception at all, then it is implementation-defined whether or not the stack is unwound (15.3/9 in C++11) before the program is terminated. It looks as though in your second test, without any catch
clauses, it is not.
This means that if you want your RAII objects to "work", then you can't allow uncaught exceptions in your program. You could do something like:
int main() {
try {
do_all_the_work();
} catch (...) {
throw; // or just exit
}
}
Now you're guaranteed that any automatic variables in do_all_the_work
will be destroyed if an exception escapes the function. The downside is that you might get less info out of your debugger, because it has forgotten the original throw site of the uncaught exception.
Of course, it's still possible for code in your program to prevent your obj
from being destroyed, for example by calling abort()
.
If you shouldn't throw exceptions in a destructor, how do you handle errors in it?
Throwing an exception out of a destructor is dangerous.
If another exception is already propagating the application will terminate.
#include <iostream>
class Bad
{
public:
// Added the noexcept(false) so the code keeps its original meaning.
// Post C++11 destructors are by default `noexcept(true)` and
// this will (by default) call terminate if an exception is
// escapes the destructor.
//
// But this example is designed to show that terminate is called
// if two exceptions are propagating at the same time.
~Bad() noexcept(false)
{
throw 1;
}
};
class Bad2
{
public:
~Bad2()
{
throw 1;
}
};
int main(int argc, char* argv[])
{
try
{
Bad bad;
}
catch(...)
{
std::cout << "Print This\n";
}
try
{
if (argc > 3)
{
Bad bad; // This destructor will throw an exception that escapes (see above)
throw 2; // But having two exceptions propagating at the
// same time causes terminate to be called.
}
else
{
Bad2 bad; // The exception in this destructor will
// cause terminate to be called.
}
}
catch(...)
{
std::cout << "Never print this\n";
}
}
This basically boils down to:
Anything dangerous (i.e. that could throw an exception) should be done via public methods (not necessarily directly). The user of your class can then potentially handle these situations by using the public methods and catching any potential exceptions.
The destructor will then finish off the object by calling these methods (if the user did not do so explicitly), but any exceptions throw are caught and dropped (after attempting to fix the problem).
So in effect you pass the responsibility onto the user. If the user is in a position to correct exceptions they will manually call the appropriate functions and processes any errors. If the user of the object is not worried (as the object will be destroyed) then the destructor is left to take care of business.
An example:
std::fstream
The close() method can potentially throw an exception.
The destructor calls close() if the file has been opened but makes sure that any exceptions do not propagate out of the destructor.
So if the user of a file object wants to do special handling for problems associated to closing the file they will manually call close() and handle any exceptions. If on the other hand they do not care then the destructor will be left to handle the situation.
Scott Myers has an excellent article about the subject in his book "Effective C++"
Edit:
Apparently also in "More Effective C++"
Item 11: Prevent exceptions from leaving destructors
Related Topics
Scale and Rotation Template Matching
Why Does C++ Code Missing a Formal Argument Name in a Function Definition Compile Without Warnings
Template Function as a Template Argument
Why Is the Copy-Constructor Argument Const
Can a Cast Operator Be Explicit
Is Rvo (Return Value Optimization) Applicable for All Objects
So Can Unique_Ptr Be Used Safely in Stl Collections
Cmake Externalproject_Add() and Findpackage()
What Is the Past-The-End Iterator in Stl C++
Converting Bool to Text in C++
Debugging Template Instantiations
Performance Cost of Passing by Value VS. by Reference or by Pointer
Why Is It Not Possible to Overload Class Templates
Using Vector<Char> as a Buffer Without Initializing It on Resize()
Are There Gotchas Using Varargs with Reference Parameters
"Symbol(S) Not Found for Architecture X86_64" on Qtcreator Project
Why am I Getting an Error Converting a 'Float**' to 'Const Float**'