Why is an object's destructor not called when an exception is thrown from its constructor?

Viewed 105

Can anyone explain me why the output of the below snippet is :

MyClass constructor
catch block

Why is the destructor of object m not been called as the scope of it is within try block?
When it comes to catch block with throw 0; statement, the object m of MyClass is out of scope and its destructor should have been invoked right?

Am i missing some kind of concept hear?

class MyClass {                                                                 
public:                                                                     
    MyClass() {                                                                 
        std::cout << "\nMyClass constructor" ;                                  
        throw 0;                                                                
    }                                                                           
    ~MyClass() {                                                                      
        std::cout << "\nMyClass destructor" << std::endl;                       
    }                                                                           
};                                                                              

int main(void)                                                                  
{                                                                               
    try {                                                                       
        MyClass m;                                                            
    } catch(int e) {                                                            
        std::cout << "\ncatch block" << std::endl;                              
    }                                                                           

    return 0;                                                                   
}    
3 Answers

According to

[dcl.init]/21

An object whose initialization has completed is deemed to be constructed, even if no constructor of the object’s class is invoked for the initialization.

And

[class.dtor]/12

A destructor is invoked implicitly

  • for a constructed object with static storage duration (6.7.1) at program termination (6.6.4),
  • ...

When an exception is thrown from a constructor, the object's initialization is not completed, the object is not deemed constructed and no destructor is called since there is infact no object.

Why is an object's destructor not called when an exception is thrown from its constructor?

  • Logically: because it was never constructed, so there's nothing to destroy.

    An object's lifetime only begins when the constructor completes successfully.

  • Practically: if you throw an exception part-way through construction, how would a destructor know which parts of the object were created (and should be destroyed), and which are just un-initialized memory? This scheme could not possibly work.

So, the destructor can't be used to "undo" a failed constructor; it's automatically handled as part of stack unwinding instead. For example, consider:

class A;
class B;
class C;
class D : public A, B {
  C m_c;
  D() : A(), B(), m_c() {}
};
  1. first, storage is allocated for D. If this step is dynamic, and fails, std::bad_alloc is thrown (and the D instance never started existing)
  2. then A::A() initializes the first (A) base-class subobject. If this fails, the subobject never started existing, the storage allocation is unwound, etc.
  3. if A::A() succeeds, B::B() initializes the second base-class subobject. If this throws, A::~A() is automatically used to destroy the A subobject.
  4. if both base-class subobjects succeed, C::C() is used to initialize the member object: if this throws, both the A and B base-class subobjects are destroyed in reverse order
  5. if all the A, B and C subobjects were constructed normally, only then is the body of D::D() (the part inside the {}, after the initializer list) entered. If this throws, the C, B and A objects are destroyed (in that order: it's always reverse order of construction)
  6. only if all those steps succeed, a new instance of D has started its lifetime. This will be destroyed with D::~D() when its lifetime ends.

UKMonkey is right. See his comment. As you raised an exception in constructor, it could not instantiate the object m. As no object exist so no call to destructor. That is the reason we must be very careful while throwing exception from a constructor. Just comment out throw 0; and check. You will understand it.

Related