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
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
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.
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 typeMyClass
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 insertingstd::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.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:
EDIT 1:
But if the exception happens in the
main()
, ie after theMyClass
object is fully instantiated, will theMyClass
destructor be invoked?Yes, it will be!
That is the purpose of using
scoped_ptr
, Once an exception is thrown inmain
, Stack Unwinding would cause all local objects to be deallocated, this means thatmyinst
(which resides on stack) will also be deallocated, which in turn will call the destructor ofMyClass
.Refer the Boost doccumentation when in doubt:
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 callabort()
.It is implementation defined behavior whether stack is Unwound beforeterminate()
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:
Ref1C++03 15.5.1 The terminate() function