Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What order are destructors called and member variables destroyed in C++ using inhertitance?

Very similar question as these, except not exactly: What is the order in which the destructors and the constructors are called in C++ Order of member constructor and destructor calls

I want to know: are the member variables of the derived class destroyed before or after the destructor of the base class is called?

This is in C++ using Visual Studio 2008. Thanks.

like image 938
mczarnek Avatar asked Feb 05 '15 23:02

mczarnek


People also ask

In what order are destructors called?

Destructors for virtual base classes are called in the reverse order of declaration.

Which destructor will be called first?

The destructor for a class object is called before destructors for members and bases are called. Destructors for nonstatic members are called before destructors for base classes are called.

In what order destructors are executed in the inheritance hierarchy?

Class E (member object 1) destructor is called and finishes. Class C (base of F) destructor is called and finishes.

How destructors are called in inheritance?

Destructors are called automatically when a variable goes out of scope. Because the base class destructor is inherited, and because the derived class object "is" a base class object, both the derived class destructor (even if it is the "default" destructor) and the base class destructor are called automatically.

When constructor is called in single inheritance in C++?

In single inheritance, firstly, Child class destructors are called and then the parent class destructors are called. Let’s see the invocation of constructors and Destructors in Single inheritance in C++. The derived class constructor called second.

How are all destructors called in C++?

All destructors are called as if they were referenced with a qualified name, that is, ignoring any possible virtual overriding destructors in more derived classes. Bases and members are destroyed in the reverse order of the completion of their constructor (see 12.6.2).

What is the sequence of invocation of constructors and destructors in C++?

The sequence of invocation of constructors and Destructors in C++ is different in different situations. Let’s see them one by one. Let’s see the order of invocation of constructors and Destructors in C++ having a simple Class. First: T4Tutorials class constructor. Second: T4Tutorials class destructor.

What is the Order of construction and destruction of destructors?

Destructors for nonstatic member objects are called in the reverse order in which they appear in the class declaration. The optional member initialization list used in construction of these members does not affect the order of construction or destruction. Destructors for non-virtual base classes are called in the reverse order of declaration.


2 Answers

constructor: first base, then derived

destruction:

  • ~derived
  • ~member derived
  • ~base
  • ~member base

code:

class member {
    string s;

public:
    member(string s) {
        this-> s = s;
    }

    ~member() {
        cout << "~member " << s << endl;
    }
};

class base {
    member m;
public:
    base() : m("base"){
    }

    ~base() {
        cout << "~base" << endl;
    }
};

class derived : base{
     member m2;
public:

    derived() :m2("derived") {    }

    ~derived() {
        cout << "~derived" << endl;
    }
};

int main(int argc, const char * argv[]) {
    derived s;

    return 0;
}

References & virtual destructor

When you plan to dynamically allocate (i.e. when you use the keywords new & delete) a derived object, then always have a virtual or a protected destructor on your base. Dynamically deleting the object on the base class reference would otherwise lead to memory leaks in the example below:

class base {
    member m;
public:
    base() : m("base"){
    }

    /* correct behaviour is when you add **virtual** in front of the signature */
    ~base() {
        cout << "~base" << endl;
    }
};

class derived : public base{
     member m2;
    char* longArray;
public:

    derived() :m2("derived") {
        longArray = new char[1000];
    }


    ~derived() {
        delete[] longArray; // never called
        cout << "~derived" << endl;
    }
};

int main(int argc, const char * argv[]) {
    base *s = new derived; // mind the downcast to **base**

    delete s; /* only the non-virtual destructor on the base and its members is called. 
               No destructor on derived or its members is called.
               What happens to the memory allocated by derived?
               **longArray** is leaked forever. 
               Even without **longArray**, it most probably **leaks** memory, as C++ doesn't define its behaviour 
               */
    return 0;
}

Output:

  • ~base
  • ~member base

Only base data is cleaned up, and longArray leaks.

like image 163
tofi9 Avatar answered Oct 07 '22 11:10

tofi9


Here's what the standard says... (C++11, 12.4/8)

After executing the body of the destructor and destroying any automatic objects allocated within the body, a destructor for class X calls the destructors for X’s direct non-variant non-static data members, the destructors for X’s direct base classes and, if X is the type of the most derived class (12.6.2), its destructor calls the destructors for X’s virtual base classes. All destructors are called as if they were referenced with a qualified name, that is, ignoring any possible virtual overriding destructors in more derived classes. Bases and members are destroyed in the reverse order of the completion of their constructor (see 12.6.2). A return statement (6.6.3) in a destructor might not directly return to the caller; before transferring control to the caller, the destructors for the members and bases are called. Destructors for elements of an array are called in reverse order of their construction (see 12.6).

Note that this order is indeed the reverse of the order given in 12.6.2/10 in C++11. You can't tell what the order of destruction of virtual bases is from looking at 12.4/8 alone, but you can infer it from 12.6.2/10, which specifies that initialization of virtual bases occurs in depth-first search left-to-right order. (Thus, destruction of virtual bases occurs in the reverse of that order.)

Anyway, you have your answer. Non-static members are destroyed first, then base classes. But a base class's members will be destroyed before the next base class's destructor starts. It really is exactly like depth-first search.

like image 11
Brian Bi Avatar answered Oct 07 '22 10:10

Brian Bi