Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happens to base class destructor if a derived class destructor throws an exception

Tags:

It just happened to me I wondered how resources are freed in the following case.

class Base {   Resource *r;  public:   Base() { /* ... */ }   ~Base() {     delete r;    } };  class Derived : public Base { public:   Derived() { /* ... */ }   ~Derived() {     /* Suddenly something here throws! */   } };  int main() {   try {     Derived d;   } catch(...) {     /* what happened with Base::r !? */   } } 

Will the base class destructor be called if the derived class destructor throws? Or will there be a leak?

like image 948
Johannes Schaub - litb Avatar asked Dec 22 '10 11:12

Johannes Schaub - litb


People also ask

Is destructor called when exception is thrown?

Yes, destructors are guaranteed to be called on stack unwinding, including unwinding due to exception being thrown. There are only few tricks with exceptions that you have to remember: Destructor of the class is not called if exception is thrown in its constructor.

When a derived class object is destroyed in what order are the destructors executed?

The body of an object's destructor is executed, followed by the destructors of the object's data members (in reverse order of their appearance in the class definition), followed by the destructors of the object's base classes (in reverse order of their appearance in the class definition).

Will the destructor be called if the constructor throws exception?

When an exception is thrown from a constructor, the object is not considered instantiated, and therefore its destructor will not be called. But all destructors of already successfully constructed base and member objects of the same master object will be called.

Does derived destructor call base destructor?

A derived class's destructor (whether or not you explicitly define one) automagically invokes the destructors for base class subobjects. Base classes are destructed after member objects.


1 Answers

According to §15.2/2:

An object that is partially constructed or partially destroyed will have destructors executed for all of its fully constructed subobjects, that is, for subobjects for which the constructor has completed execution and the destructor has not yet begun execution.

So the base class destructor should be called. That is, just like we know this will clean up the base class:

#include <iostream>  struct foo {     ~foo()     {         std::cout << "clean" << std::endl;     } };  struct bar : foo {     bar()     { // foo is initialized...         throw 0; // ...so its destructor is run     } };  int main() {     try     {         bar b;     }     catch (...)     {         std::cerr << "caught" << std::endl;     } } 

And that this will clean up the member:

#include <iostream>  struct foo {     ~foo()     {         std::cout << "clean" << std::endl;     } };  struct bar {     ~bar()     { // f has been initialized...         throw 0; // ...so its destructor will run     }      foo f; };  int main() {     try     {         bar b;     }     catch (...)     {         std::cerr << "caught" << std::endl;     } } 

This will also clean up the base class:

#include <iostream>  struct foo {     ~foo()     {         std::cout << "clean" << std::endl;     } };  struct bar : foo {     ~bar()     { // foo has been initialized...         throw 0; // ...so its destructor will run     } };  int main() {     try     {         bar b;     }     catch (...)     {         std::cerr << "caught" << std::endl;     } } 

That's my understanding of the quote.

like image 81
GManNickG Avatar answered Sep 21 '22 22:09

GManNickG