Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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
"; }
~MyClass() { std::cout<<"MyClass De-allocated
"; }
int increment() { return ++*ptr; }
};

int main()
{
    boost::scoped_ptr<MyClass> myinst(new MyClass);
    std::cout << myinst->increment() << '
';
    std::cout << myinst->increment() << '
';
}

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
"; }
    ~MyClass() { std::cout<<"MyClass De-allocated
"; }
    int increment() { return ++*ptr; }
};

int main()
{
    boost::scoped_ptr<MyClass> myinst(new MyClass);
    throw 3;
    std::cout << myinst->increment() << '
';
    std::cout << myinst->increment() << '
';
}

Output:

MyClass Allocated
terminate called after throwing an instance of 'int'
Aborted
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
160 views
Welcome To Ask or Share your Answers For Others

1 Answer

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
"; } 
    ~MyClass() { std::cout<<"MyClass De-allocated
"; } 
    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,

  1. 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().


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...