64

What is the order in which the destructors and the constructors are called in C++? Using the examples of some Base classes and Derived Classes

Daniel Daranas
  • 22,454
  • 9
  • 63
  • 116
hozefam
  • 980
  • 1
  • 7
  • 13

5 Answers5

80

The order is:

  1. Base constructor
  2. Derived constructor
  3. Derived destructor
  4. Base destructor

Example:

class B
{
public:
  B()
  {  
    cout<<"Construct B"<<endl;
  }

  virtual ~B()
  {
    cout<<"Destruct B"<<endl;
  }
};

class D : public B
{
public:
  D()
  {  
    cout<<"Construct D"<<endl;
  }

  virtual ~D()
  {
    cout<<"Destruct D"<<endl;
  }
};



int main(int argc, char **argv)
{
  D d; 
  return 0;
}

Output of example:

Construct B

Construct D

Destruct D

Destruct B

Multiple levels of inheritance works like a stack:

If you consider pushing an item onto the stack as construction, and taking it off as destruction, then you can look at multiple levels of inheritance like a stack.

This works for any number of levels.

Example D2 derives from D derives from B.

Push B on the stack, push D on the stack, push D2 on the stack. So the construction order is B, D, D2. Then to find out destruction order start popping. D2, D, B

More complicated examples:

For more complicated examples, please see the link provided by @JaredPar

Piranna
  • 1,697
  • 1
  • 14
  • 16
Brian R. Bondy
  • 339,232
  • 124
  • 596
  • 636
22

A detailed description of these events, including virtual and multiple inheritance is available at the C++ FAQ Lite. Section 25.14 and 25.15

https://isocpp.org/wiki/faq/multiple-inheritance#mi-vi-ctor-order

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
10

Also, keep in mind that while array elements are constructed first -> last, they are destructed in the reverse order: last -> first.

Ferruccio
  • 98,941
  • 38
  • 226
  • 299
  • 3
    +1 That is true for mostly everything. Order of destruction is always the opposite of construction. Static variables have no guaranteed order of construction, but destruction will happen in reversed order. – David Rodríguez - dribeas Mar 17 '09 at 21:59
  • 1
    Is that (expected) templatized container behavior and/or built-in `new []` / `delete []` behavior? – franji1 Feb 02 '16 at 18:35
9

I must add to the previous answers because everyone seems to be ignoring it

When you have a derived class instance being created, it is true that the code inside the constructor of the base will be called before the code inside the constructor of the derived, but keep in mind that the derived is still technically "created" before the base.

And when you have the derived class destructor being called, it is true that the code inside the derived destructor is called before the code inside the base destructor, but also keep in mind that the base is destroyed before the derived.

When I am saying created/destroyed I am actually referring to allocated/deallocated.

If you look at the memory layout of these instances, you will see that the derived instance composes the base instance. For example:

Memory of derived: 0x00001110 to 0x00001120

Memory of base : 0x00001114 to 0x00001118

Therefore, the derived class must be allocated BEFORE the base in the construction. And the derived class must be deallocated AFTER the base in the destruction.

If you have the following code:

class Base 
{
public:
    Base()
    {
        std::cout << "\n  Base created";
    }
    virtual ~Base()
    {
        std::cout << "\n  Base destroyed";
    }
}

class Derived : public Base 
{
public:
    Derived()
    // Derived is allocated here 
    // then Base constructor is called to allocate base and prepare it
    {
        std::cout << "\n  Derived created";
    }
    ~Derived()
    {
        std::cout << "\n  Derived destroyed";
    }   
    // Base destructor is called here
    // then Derived is deallocated
}

So if you created Derived d; and had it go out of scope, then you will get the output in @Brian's answer. But the object behavior in memory is not really the in same order, it is more like this:

Construction:

  1. Derived allocated

  2. Base allocated

  3. Base constructor called

  4. Derived constructor called

Destruction:

  1. Derived destructor called

  2. Base destructor called

  3. Base deallocated

  4. Derived deallocated

Everyone
  • 1,751
  • 13
  • 36
  • That is a nice clarification. Memory is allocated first for the derived classes, then the base, but the construction happens first for the base class then the derived class. For destruction, the last one added to the "stack" is destructed, ie, the derived class, then the base. But deallocation happens in the opposite order, first base, then derived. – nnrales Mar 26 '18 at 22:18
  • Do you know why this happens ? This is interesting to me. – nnrales Mar 26 '18 at 22:18
  • @nnrales this follows the composition relationship. When you declare a `std::string` for example (not pointer) in the class, the string is also allocated after the composer but its constructor is called before. The derived composes the base and contains it in its memory space and so the derived has to be allocated first. If you print the addresses this will be clarified better. You can even get access to the base instance by casting `this` in derived to the base and use it to do some operations. – Everyone Mar 26 '18 at 22:33
2

This is clearly described at order-dtors-for-members. Basically, the rule is "First constructed, last destructed."

Constructors calling order:

  1. base's constructors are called in the order of appearance after the ":"
  2. derived class member's constructors are called in the order of appearance and before class's constructor

Destructors are called in reversed order of called constructors.

Example:

#include <iostream>

struct base0 {  base0(){printf("%s\n", __func__);};~base0(){printf("%s\n", __func__);}; };
struct base1 { base1(){printf("%s\n", __func__);}; ~base1(){printf("%s\n", __func__);};};
struct member0 { member0(){printf("%s\n", __func__);};  ~member0(){printf("%s\n", __func__);};};
struct member1 { member1(){printf("%s\n", __func__);}; ~member1(){printf("%s\n", __func__);};};
struct local0 { local0(){printf("%s\n", __func__);}; ~local0(){printf("%s\n", __func__);}; };
struct local1 { local1(){printf("%s\n", __func__);};  ~local1(){printf("%s\n", __func__);};};
struct derived: base0, base1
{
  member0 m0_;
  member1 m1_;
  derived()
  {
    printf("%s\n", __func__);
    local0 l0;
    local1 l1;
  }
  ~derived(){printf("%s\n", __func__);};
};
int main()
{
  derived d;
}

Output:

base0
base1
member0
member1
derived
local0
local1
~local1
~local0
~derived
~member1
~member0
~base1
~base0