3

I coded the following classes in order to test the multi-level inheritance concept. There is a point that I didn't really understand when I was trying to test the calls to constructors and destructors.


#include <iostream>

using namespace std;

class X{

    public:
        X(){cout <<"Construct X " << endl;};
        virtual ~X(){cout <<"Destruct X " << endl;};
        virtual void print() const = 0;
};

class Y: public X{
    public:
        Y(){cout <<"construct Y " << endl;};
        ~Y(){cout <<"Destruct Y " << endl;};
        void print() const{
            cout <<"print Y" << endl;
        };
};

class Z: public Y{
    public:
        Z(){cout <<"Construct Z" << endl; };
        ~Z(){cout <<"Destruct Z " << endl; };
        void print() const{
            cout <<" Print Z" << endl;
        };
};

int main()
{
    Y y;
    //Why isn't Y being destructed in here
    Z z;
    return 0;
}

Output

The output is the following. I understood that we start from the base class. So in Y y; first the constructor of X is called, then Y. In Z z; first the construct of X is called, then Y and finally Z.

Construct X
construct Y
Construct X
construct Y
Construct Z
Destruct Z
Destruct Y
Destruct X
Destruct Y
Destruct X

Question

  • Why isn't the destructor for Y being called right after Y y;. Why should we wait till Z is constructed then call the destructors. Meaning why doesn't the output look like that:

    Construct X
    construct Y
    Destruct Y
    Destruct X
    Construct X
    construct Y
    Construct Z
    Destruct Z
    Destruct Y
    Destruct X
    
mch
  • 9,424
  • 2
  • 28
  • 42
Hani Gotc
  • 840
  • 11
  • 24
  • 3
    That would mean the `y` is destroyed before `z` is constructed. Is that what you expect? How would you use `y` afterwards? – xinaiz Feb 20 '17 at 14:48
  • 1
    Possible duplicate of [C++ local variable destruction order](http://stackoverflow.com/questions/14688285/c-local-variable-destruction-order) – LogicStuff Feb 20 '17 at 14:49
  • 1
    @HaniGotc: If you want a variable to be destroyed early, you need to enclose it in a block: `int main() { {Y y; } Z z; }`. This can be useful if 'Y' is actually a class to obtain a lock, and you want to release the lock early. – Martin Bonner supports Monica Feb 20 '17 at 15:01

3 Answers3

8

Inheritance is a red herring here. It's not relevant.

y and z have automatic storage duration and are required, in this case, to stay in scope until the closing brace of the function.

And z will be destructed before y. (Automatic variables go out of scope in the reverse order in which they were created, all other things being equal.)

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • (Note that a optimising compiler can break this rule so long as there are no side effects in it doing so - which there would be in in this case.) – Bathsheba Feb 20 '17 at 14:54
  • Z is destroyed before y. Because they are placed on the stack right? Last In first out – Hani Gotc Feb 20 '17 at 14:55
  • 1
    You can *think* in terms of a stack, but I'm careful not to introduce the term as it's an implementation concept, not a language concept (despite a couple of newer std:: functions alluding to it). – Bathsheba Feb 20 '17 at 14:57
  • 1
    @HaniGotc: Actually, because there might be a dependency. Since z is defined after y, z can hold a reference to y. For that to work reliably, the lifetime of z must be strictly smaller than that of y. – MSalters Feb 20 '17 at 15:02
4

This is unrelated to inheritance. Variables declared in block scope are destroyed when that block is left, i.e. a return statement is taken or the final } is reached or an exception is thrown.

melpomene
  • 84,125
  • 8
  • 85
  • 148
MSalters
  • 173,980
  • 10
  • 155
  • 350
0

The objects exist at the end of their scope, and the objects get destroyed in reverse order of their construction.

y is constructed first, then z. So, when their mutual scope's end is reached, z gets destroyed first, then y.

You were expecting the objects to be destroyed in the same order they were constructed, but they actually get destroyed in reverse order of construction.

Similarly, when an object gets constructed, its base class is constructed first, then the derived class. When the object gets destroyed, the derived class gets destroyed first, then the base class.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148