c++objectoutputdestructor

Why is the destructor called twice here?


Consider the below code:

#include <iostream>

struct Person {
    Person() { std::cout << "A"; }              // Constructor
    Person(const Person& other) { std::cout << "B"; }  // Copy constructor
    ~Person() { std::cout << "D"; }             // Destructor
};

struct Student : public Person { // Correct inheritance
    Student() { std::cout << "a"; }              // Constructor
    Student(const Student& other) : Person(other) { std::cout << "b"; }  // Copy constructor
    ~Student() { std::cout << "d"; }             // Destructor
};

int main() {
    Student* s1 = new Student;   // Create Student object on heap
    Student s2 = *s1;             // Call copy constructor
    *s1 = s2;                    // Use copy assignment operator
    delete s1;                   // Delete the dynamically allocated memory
    return 0;
}

The output is AaBbdDdD. I do not understand why the destructor is seemingly called twice in this example. Could you please explain this to me?


Solution

  • The short explanation is that two objects are created and the same two are destroyed, resulting in destruction of two objects.

    In more detail, I'll step through your main().

    Firstly,

    Student* s1 = new Student; 
    

    dynamically allocates a Student (which calls constructors of Person and Student in order) and s1 is initialised to point at that object. Then ....

    Student s2 = *s1;
    

    creates a second object named s2, and initialises it as a COPY (using copy constructor) of the object pointed to by s1.

    The next statement

    *s1 = s2;
    

    assigns the object pointed to by s1 to become a copy of the distinct object s2. This statement neither creates nor destroys a Student, so no constructor and no destructor are called.

    The statement

    delete s1;
    

    then explicitly destroys the object pointed to by s1. One step in destroying that object is a call of the destructor (the first destructor call you observe).

    main() then returns so all objects of automatic storage duration defined within main() are automatically destroyed. Hence s2 is destroyed and, in that process, it's destructor called. That is the second destructor call you observe.