Tom Xue
Tom Xue

Reputation: 3355

Please explain the sequence of destructor invocations

using namespace std;

class C
{
    int a;
    public:
        C(int aa=0) {a=aa;}
        ~C() {cout << "Destructor C!" << a << endl;}
};

class D: public C
{
    int b;
    public:
        D(int aa=0, int bb=0): C(aa) {b=bb;}
        ~D() {cout << "Destructor D!" << b << endl;}
};

void test()
{
    D x(5);
    D y(6,7);
}

int main()
{
    test();
}

Above is the code, and below is the running result:

Destructor D!7
Destructor C!6
Destructor D!0
Destructor C!5

I don't understand why "Destructor C!" will be invoked. And the related destructor's calling sequence. I feel that it seems like the stack push/pop.

Further: Why it calls "D x(5);" earlier but the corresponding result is given later?

Upvotes: 2

Views: 4999

Answers (8)

Flint
Flint

Reputation: 1691

Further: Why it calls "D x(5);" earlier but the corresponding result is given later?

These objets are allocated on the stack (while D * d1 = new D(); would allocate on the heap).

It is not the call to D x(5) which gives output, but the call to the destructor ~D occuring when the instance gets out of scope, in this case, when exiting main().

Because it's stack memory, the desallocations occur in reverse order to the allocation;

Upvotes: 0

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726479

The destructor calling sequence always goes from the derived to base, like popping the stack. This allows derived classes to clean up resources allocated by your base class. In this case, the compiler knows how to construct this sequence, because it knows the exact type of the objects x and y statically.

There are situations, however, when this sequence would be broken. Consider the following modification of your code:

void test()
{
    C *x = new D(5);
    D *y = new D(6,7);
    delete x;
    delete y;
}

It produces the following output:

Destructor C!5
Destructor D!7
Destructor C!6

Running this produces no call of ~D for x; for y, both destructors are called.

This is because you did not declare the destructor virtual in the base class. When the destructor is not virtual, the compiler has no idea that it must call the destructor of the derived class in situations when an object is referred to by a pointer to a base class. This is why you should always make a destructor virtual in classes that must be inherited and allocate resources dynamically.

Upvotes: 3

billz
billz

Reputation: 45410

 I feel that it seems like the stack push/pop.

class D derived from C, when call D constructor, C constructor will be called first, destructor is called the reverse way.

Further: Why it calls "D x(5);" earlier but the corresponding result is given later?

Automatic objects (commonly referred to as "local variables") are destructed, in reverse order of their definition, when control flow leaves the scope of their definition.

Upvotes: 2

The destructor of C is called because destroying an object of a derived class includes destroying its base class subobject. As per [class.dtor] para 8:

After executing the body of the destructor ... a destructor for class X calls ... the destructors for X's direct base classes ...

When control flow exits a scope (such as your function test() ending), local objects are destroyed in LIFO manner: objects created first are destroyed last. As per [stmt.jump] para 2:

On exit from a scope (however accomplished), objects with automatic storage duration (3.7.3) that have been constructed in that scope are destroyed in the reverse order of their construction.

Upvotes: 0

HAL
HAL

Reputation: 3988

The constructor and destructor calling sequence for a derived class is as follows:

Base  Class  Constructor
Derived  Class  Constructor
Derived  Class  Destructor
Base  Class  Destructor

As a derived class is built on top a base class:

  • the base class has to be constructed before the derived class.
  • the derived class has to be destroyed before the base class.

Upvotes: 3

tomahh
tomahh

Reputation: 13651

When you inherit, you "extend" the object you inherit from. So if you want to build D, you need C. And when you need to destroy D, you will the destroy C, which you build to be able to extend it.

Upvotes: 1

Tony The Lion
Tony The Lion

Reputation: 63190

When you create a D instance, the constructor of C will be called because D inherits from it.
When you destroy D again, it'll call Ds destructor and then C destructor.

Upvotes: 1

Thirler
Thirler

Reputation: 20760

When an objected is cleaned up, first the destructor of the derived class is called, then the destructor of the base class.

Upvotes: 1

Related Questions