I have read that it is not a good idea to throw from a destructor because of stack unwinding. I am not sure I understand that fully. So I tried the following example
struct foo
{
~foo()
{
throw 1;
}
};
struct bar
{
~bar()
{
throw 2;
}
};
int main()
{
try
{
foo a;
bar b;
throw 3;
}catch(int a)
{
std::cout << a;
}
}
Now I was expecting that the a would be 1 because first 3 is thrown then destructor of b is called which throws 2 and then destructor of a is called which throws 1. Apparently this is not the case and this might explain why its not a good idea to throw from destructors. My question is why was abort() called the destructor of b was called ?
Throwing an exception during stack-unwinding this will lead to std::terminate being called whose default action is to call std::abort.
CERT has a good explanation in their ERR33-CPP. Destructors must not throw exceptions document which says (emphasis mine):
A destructor is very likely to be called during stack unwinding
resulting from an exception being thrown. If the destructor itself
throws an exception, having been called as the result of an exception
being thrown, then the function std::terminate() is called with the
default effect of calling std::abort(). This could provide the
opportunity for a denial-of-service attack. Hence, destructors must
satisfy the no-throw guarantee, that is, they must not throw an
exception if they themselves have been called as the result of an
exception being thrown.
This is covered in the draft C++ standard section 15.2 Constructors and destructors which says:
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 ]
Note that in C++11 destructors are specified implicitly noexcept(true) as long as none of the functions it calls allows exceptions. So in this case throwing from a destructor would call std::terminate regardless.
From section 12.4 Destructors:
A declaration of a destructor that does not have an
exception-specification is implicitly considered to have the same
exception-specification as an implicit declaration (15.4).
and 15.4 says:
An implicitly declared special member function (Clause 12) shall have
an exception-specification. If f is an implicitly declared default
constructor, copy constructor, move constructor, destructor, copy
assignment operator, or move assignment operator, its implicit
exception-specification specifies the type-id T if and only if T is
allowed by the exception-specification of a function directly invoked
by f’s implicit definition; f shall allow all exceptions if any
function it directly invokes allows all exceptions, and f shall allow
no exceptions if every function it directly invokes allows no
exceptions.
Theoretically you could use std::uncaught_exception to detect stack-unwinding in the destructor but in GotW #47 Herb Sutter explains why this technique is not as useful as it seems.
Although Herb has very recently proposed a fix in N4152: uncaught
_exceptions
Whenever you throw an exception while exception processing is ongoing, you get a special exception that can't be caught and this leads to an abort.
You can use std::uncaught_exception to detect if exception handling is already in progress and avoid throwing in that case.
Others have answered from the standard, but I think another example illustrates the conceptual problem best:
struct foo {
char *buf;
foo() : buf(new char[100]) {}
~foo() {
if(buf[0] == 'a')
throw 1;
delete[] buf;
}
};
int main() {
foo *f = new f;
try {
delete f;
} catch(int a) {
// Now what?
}
}
This is a bit simplistic, of course, but shows the problem. What's the right thing for delete f to have done? Whichever way it goes, you end up with either a partially destructed object or a memory leak.
On some cases it is possible to add an exception specification like this and handle them with safety. Note that the object is only deleted when no exception is thrown.
#include<iostream>
using namespace std;
struct A{
bool a;
A():a(1){}
~A()throw(int){
if(a)a=0,throw 0;
}
};
int main(){
A*a=new A();
try{
delete a;
}catch(int&){
delete a;
cout<<"here"<<endl;
}
return 0;
}
Related
From other threads, I know we should not throw exception in destructor! But for below example, it really works. Does that means we can only throw exception in one instance's destructor? how should we understand this code sample!
#include <iostream>
using namespace std;
class A {
public:
~A() {
try {
printf("exception in A start\n");
throw 30;
printf("exception in A end\n");
}catch(int e) {
printf("catch in A %d\n",e);
}
}
};
class B{
public:
~B() {
printf("exception in B start\n");
throw 20;
printf("exception in B end\n");
}
};
int main(void) {
try {
A a;
B b;
}catch(int e) {
printf("catch in main %d\n",e);
}
return 0;
}
The output is:
exception in B start
exception in A start
catch in A 30
catch in main 20
Best practice prior to C++17 says to not let exceptions propagate out of a destructor. It is fine if a destructor contains a throw expression or calls a function that might throw, as long as the exception thrown is caught and handled instead of escaping from the destructor. So your A::~A is fine.
In the case of B::~B, your program is fine in C++03 but not in C++11. The rule is that if you do let an exception propagate out of a destructor, and that destructor was for an automatic object that was being directly destroyed by stack unwinding, then std::terminate would be called. Since b is not being destroyed as part of stack unwinding, the exception thrown from B::~B will be caught. But in C++11, the B::~B destructor will be implicitly declared noexcept, and therefore, allowing an exception to propagate out of it will call std::terminate unconditionally.
To allow the exception to be caught in C++11, you would write
~B() noexcept(false) {
// ...
}
Still, there would be the issue that maybe B::~B is being called during stack unwinding---in that case, std::terminate would be called. Since, before C++17, there is no way to tell whether this is the case or not, the recommendation is to simply never allow exceptions to propagate out of destructors. Follow that rule and you'll be fine.
In C++17, it is possible to use std::uncaught_exceptions() to detect whether an object is being destroyed during stack unwinding. But you had better know what you're doing.
The recommendation that "we should not throw exception in destructor" is not an absolute. The issue is that when an exception is thrown the compiler starts unwinding the stack until it finds a handler for that exception. Unwinding the stack means calling destructors for objects that are going away because their stack frame is going away. And the thing that this recommendation is about occurs if one of those destructors throws an exception that isn't handled within the destructor itself. If that happens, the program calls std::terminate(), and some folks think that the risk of that happening is so severe that they have to write coding guidelines to prevent it.
In your code this isn't a problem. The destructor for B throws an exception; as a result, the destructor for a is also called. That destructor throws an exception, but handles the exception inside the destructor. So there's no problem.
If you change your code to remove the try ... catch block in the destructor of A, then the exception thrown in the destructor isn't handled within the destructor, so you end up with a call to std::terminate().
EDIT: as Brian points out in his answer, this rule changed in C++11: destructors are implicitly noexcept, so your code should call terminate when the the B object is destroyed. Marking the destructor as noexcept(false) "fixes" this.
I'm trying to write a unit test that detects an invalid use of the lock() feature of my class. In order to do so, I want to use the destructor and throw an exception from there. Unfortunately, instead of catching the exception, g++ decides to call std::terminate().
There is a very simplified version of the class:
class A
{
public:
A() : f_lock(0) {}
~A() { if(f_lock) throw my_exception("still locked"); }
lock() { ++f_lock; }
unlock() { --f_lock; }
private:
int f_lock;
};
There is a valid test:
A *a = new A;
a->lock();
...
a->unlock();
delete a;
There is the invalid test I'm trying to write:
A *a = new A;
a->lock();
...
bool success = false;
try
{
delete a;
}
catch(my_exception const&)
{
success = true;
}
catch(...)
{
// anything else is a failure
}
if(!success)
{
// test failed...
CPPUNIT_ASSERT(!"test failed");
}
Right now, the delete calls std::terminate() even though the throw is not being called when another exception is active. (i.e. std::uncaught_exception() is false.) And also I clearly am catch all exceptions!
Am I doing something wrong, or is g++ programmed to do that always in destructors?
Update:
The answer by dyp in the comments below works! The following does not directly call std::terminate():
~A() noexcept(false) { throw ...; }
Also for reference about why you do not want a throw in a destructor, this page is excellent;
https://www.securecoding.cert.org/confluence/display/cplusplus/ERR33-CPP.+Destructors+must+not+throw+exceptions
For clarification, there is the full version of the destructor. As we can see I first post a message (it generally goes in your console, may go to a log too). Second I make sure we're not already managing an exception. Finally, I throw an exception named exception_exit which is expected to force a terminate() although in a GUI application you may want to show a MessageBox of some sort to let the user know something happened (since you can capture the Message, you can display that to the user) and then force an application shut down.
Node::~Node() noexcept(false)
{
if(f_lock > 0)
{
// Argh! A throw in a destructor... Yet this is a fatal
// error and it should never ever happen except in our
// unit tests to verify that it does catch such a bug
Message msg(message_level_t::MESSAGE_LEVEL_FATAL, err_code_t::AS_ERR_NOT_ALLOWED);
msg << "a node got deleted while still locked.";
// for security reasons, we do not try to throw another
// exception if the system is already trying to process
// an existing exception
if(std::uncaught_exception())
{
// still we cannot continue...
std::abort();
}
throw exception_exit(1, "a node got deleted while still locked.");
}
}
Also, another detail, you are expected to use the NodeLock object to manage the f_lock flag. That is exception safe since it uses RAII (i.e. a scoped lock). However, at this point I did not want to force the user to make use of the NodeLock to lock/unlock a node, hence this test in the destructor.
In C++11 the noexcept keyword was added. This can be used in function exception specifications:
noexcept(true) is the same as throw(), i.e. this function terminates if anything is thrown
noexcept(false) means the function may throw anything
For most functions, they don't have an exception-specification unless you give them one. A function with no exception-specification may throw anything.
There is a special case for destructors though, found in C++11 [class.dtor]/3:
A declaration of a destructor that does not have an exception-specification is implicitly considered to have the same exception-specification as an implicit declaration (15.4).
The referenced rule, 15.4, says that implicitly-declared special member functions always have an exception-specification. The specification is determined by the following rule, [except.spec]/14:
An implicitly declared special member function (Clause 12) shall have an exception-specification. If f is an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-id T if and only if T is allowed by the exception-specification of a function directly invoked by f’s implicit definition; f shall allow all exceptions if any function it directly invokes allows all exceptions, and f shall allow no exceptions if every function it directly invokes allows no exceptions.
The "function it directly invokes" in this clause means the destructor of any member variable or base class (applied recursively). If there is no such function , then there are no exceptions allowed by such a function, so the default is noexcept(true).
We could summarise the portion of the above quote relating to your code like this:
If all subobjects either have no destructor, or implicitly-generated destructor, or destructor declared as noexcept(true) or equivalent; then this class's destructor defaults to noexcept(true).
So, changing your destructor to have noexcept(false) would reproduce the behaviour of C++03.
In C++03 none of this appeared and your destructor would have defaulted to allowing all exceptions. I don't know for sure why this change was made in C++11, but it may be because it is a bad idea to throw from a destructor unless you really know what you are doing.
Detailed explanation available at http://www.parashift.com/c++-faq/dtors-shouldnt-throw.html. Better explanation than my own words :)
Excerpt :
You can throw an exception in a destructor, but that exception must not leave the destructor; if a destructor exits by emitting an exception, all kinds of bad things are likely to happen because the basic rules of the standard library and the language itself will be violated. Don’t do it
I have just started using c++ boost libraries. I read in many places that when a scoped_ptr is used then the object is always destroyed even in case of exceptions.
They behave much like built-in C++ pointers except that they automatically delete the object pointed to at the appropriate time. Smart pointers are particularly useful in the face of exceptions as they ensure proper destruction of dynamically allocated objects.
I tried in the following code.
#include<boost/scoped_ptr.hpp>
class B
{
public:
B(){ std::cout<< "B constructor call\n"; }
~B(){ std::cout<<"B destructor call\n"; }
};
class A
{
public:
boost::scoped_ptr<B> b;
A():b(new B())
{
throw 1;
}
};
int main()
{
A a; return 0;
}
output:
B constructor call
terminate called after throwing an instance of 'int'
Aborted (core dumped)
There is no call to B's destructor. But I used scoped_ptr so it should have called B's destructor or did I mis-interpreted the use of scoped_ptr.
But if a surround it with try catch then B's destructor is called.
try{
A a;
} catch( ... ) {
}
In this case destructor of A will be called as all locally allocated objects in case of exception in a try block are removed from the stack and I have my pointer wrapped inside and object of scoped_ptr so when the destructor of scoped object destroys which ultimately the pointer.
So is scoped_ptr is useful because we don't have to explicitly delete the memory allocated or I mis-interpreted the description of scoped_ptr.
How can I call the destructor of class B in case of exception using scoped_ptr
There's no matching exception handler, so std::terminate is called directly, in this case without the stack being unwound. Put a try/catch in main that catches int and you'll see your destructor call, even if that handler rethrows.
C++11 §15.1/2:
When an exception is thrown, control is transferred to the nearest handler with a matching type; "nearest" means the handler for which the compound-statement or ctor-initializer following the try keyword was most recently entered by the thread of control and not yet exited.
and §15.3/9:
If no matching handler is found, the function std::terminate() is called; whether or not the stack is unwound before this call to std::terminate() is implementation-defined.
Online demo
C++ destroy a local variable when unwinding stack(return from a function, either with return keyword or with an exception), so it should see one to destroy your scoped_ptr. But in your special case, exception occurred in main so terminate will be called and kill your program before C++ unwind the stack.
void test() {throw 1;}
void main() {
string sMain;
test();
}
In above example, sMain will not destroyed because exception cause calling terminate:
sMain constructed
exception occurred: main has no where to go, and it has no handler to handle
the exception, so it will call `terminate`, but wait we are still at `main`
so we have no stack unwinding here and sMain will never destroyed!!
Why is the destructor not invoked in this code?
#include <boost/scoped_ptr.hpp>
#include <iostream>
class MyClass {
boost::scoped_ptr<int> ptr;
public:
MyClass() : ptr(new int) { *ptr = 0; throw; std::cout<<"MyClass Allocated\n"; }
~MyClass() { std::cout<<"MyClass De-allocated\n"; }
int increment() { return ++*ptr; }
};
int main()
{
boost::scoped_ptr<MyClass> myinst(new MyClass);
std::cout << myinst->increment() << '\n';
std::cout << myinst->increment() << '\n';
}
EDIT
From the answers, In understand that when an exception happens in the constructor, destructor will not be invoked. But if the exception happens in the main(), ie after the MyClass object is fully instantiated, will the MyClass destructor be invoked? If not, then why it is a smart pointer?
Adding the code
#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; }
};
int main()
{
boost::scoped_ptr<MyClass> myinst(new MyClass);
throw 3;
std::cout << myinst->increment() << '\n';
std::cout << myinst->increment() << '\n';
}
Output:
MyClass Allocated
terminate called after throwing an instance of 'int'
Aborted
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,
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().
Because calling the destructor doesn't make sense in this case.
You only destruct things which are constructed, yet your object never fully constructs. Your class members have been constructed, though, and will have their destructors called.
If a constructor throws exception, then the destructor of the class will not be called, because the object is not fully constructed.
See this link how to manage resources in such situation:
http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.10
When the exception is thrown from the constructor (beginning or half way or at the end of the call), then it's assured that the object is not constructed.
So it's well defined not to invoke the destructor of an object which was never constructed.
Here is one related FAQ from Bjarne's website.
The destructor for MyClass was never invoked because no objects of type MyClass were ever constructed. Each attempt to construct one was aborted, due to the exception being thrown.
As an aside, if you want your debug messages to display -- especially if you're dealing with the program crashing -- you really ought to flush the streams: i.e. using std::endl instead of '\n' at the end of line. (or inserting std::flush)
While merely using '\n' often works, there are enough situations where it fails and it's really, really confusing to debug if you don't make a habit of doing things right.
I was recently tasked with hunting down a memory leak in a part of our code. The leak ended up being in the destructor for a particular object...and I found something really strange. A former coworker wrote this:
File::~File()
try
{
Clear();
}
catch (...)
{
Log("caught exception");
}
The file class inherits from some base classes. My first question is: is this strictly legal C++? It compiles in Visual Studio 2008, but I showed it to a few friends / coworkers and they were fairly horrified that it worked.
It doesn't actually work as intended, though: the base class that this object inherits from has a destructor that is now never called (as opposed to if you just wrapped the destructor in a regular method block, having the try / catch as part of that method).
Can anyone take a stab at explaining why this is allowed, and why the base class destructor was not called? The destructor here was not throwing.
This is a function try block and it's completely legal.
See, for example, here.
The only time that you can do something in a function try block that you can't do in a normal try block in a function is catch exceptions thrown by expression in a constructor initializer list (and even then you end up having to throw something), but that doesn't apply here.
This GOTW #66 is particularly interesting, although it concentrates more on constructors. It contains this "moral":
Since destructors should never emit an exception, destructor function-try-blocks have no practical use at all.
Just to add clarification, the code as written will cause any exception caught to be rethrown due to ISO/IEC 14882:2003 15.3 [except.handle] / 16:
The exception being handled is rethrown if control reaches the end of a handler of the function-try-block of a constructor or destructor. [...]
However it is legal to have a parameterless return in the handler of a function try block for a destructor - it is only forbidden in a function try block for a constructor - and this will supress the rethrow of the exception. So either of these alternatives would prevent the exception from leaving the destructor.
File::~File()
try
{
Clear();
}
catch (...)
{
Log("caught exception");
return;
}
File::~File()
{
try
{
Clear();
}
catch (...)
{
Log("caught exception");
}
}
To answer the second part, "why the base class destructor was not called?", 12.4/6:
After executing the body of the
destructor and destroying any
automatic objects allocated within the
body, a destructor for class X calls
the destructors for X’s direct
members, the destructors for X’s
direct base classes...
A return statement (6.6.3) in a
destructor might not directly return
to the caller; before transferring
control to the caller, the destructors
for the members and bases are called.
This doesn't say that the member and base destructors are called if the destructor throws. However, 15.2/2 says:
An object that is partially
constructed or partially destroyed
will have destructors executed for all
of its fully constructed subobjects,
I think this should be true whether the object is "partially destroyed" because of an exception thrown from the body of the destructor, or because of an exception thrown from the the function try block of the destructor. I'm pretty sure that "after the body of the destructor" is supposed to mean also after a function try block.
Apparently Microsoft disagrees, though, and because of the function try block it hasn't generated "the body of the destructor", and hasn't done the things that happen after executing "the body of the destructor".
That doesn't sound right to me. GCC 4.3.4 does execute the base class destructor, whether the derived class dtor function try block throws or not. In the case where it throws, the base is destructed before the catch clause is executed.