tags:

views:

348

answers:

8

With regards to the sample code below, why is the destructor for the base class called twice?

class Base {
public:
    Base() {
     std::cout << "Base::Base()" << std::endl;
    }

    ~Base() {
     std::cout << "Base::~Base()" << std::endl;
    }
};

class Derived : public Base {
public:
    Derived() {
     std::cout << "Derived::Derived()" << std::endl;
    }

    ~Derived() {
     std::cout << "Derived::~Derived()" << std::endl;
    }
};

int main() {
    Base a = Derived();
    return EXIT_SUCCESS;
}

Here is a sample of the output when the program is run:

Base::Base()
Derived::Derived()
Derived::~Derived()
Base::~Base()
Base::~Base()
A: 

You need a virtual destructor.

not-too-smatr
Wrong. this has nothing to do with the bhaviour the questioner is seeing. a virtuial destructor is only required if you delete an object of a Derived class via a Base pointer, whuich is not the case here.
anon
+4  A: 

When you say Derived() in main() it creates a temporary object which is then copied into object a. Hence there are two objects because of which destructor is called twice. Also, as others pointed out your base class destructor should be virtual.

Naveen
+7  A: 

A copy constructor is being used. If you want to see what is going on, instrument the copy constructor too:

 Base( const Base & ) {
        std::cout << "Base::Base( const Base &)" << std::endl;
    }

and similarly for Derived.

Note that this has NOTHING to do with the destructors not being virtual.

anon
Furthermore, output the this pointer as well, to demonstrate that there are two objects (and object slicing).
Dave Hinton
Neil, that is it. A copy constructor is being synthesised b the compiler and used to init the base object, When the Base object is going out of scope, the destructor is called twice.
Harish H
Object slicing is also taking place, as the Base copy constructor is taking a Derived object.
Harish H
+14  A: 

What happens is called slicing. You initialize an object of type Base with an object of type Derived. Since any object of type Derived has also an object of type Base contained (called "base-class sub-object"), there will be two Base objects and one Derived object in existance throughout the program. The Derived object (and its base-class sub-object of type Base) only exists for the time of initialization, while the remaining Base object exists until end of main.

Since there are two Base objects and one Derived object, you will also see one more Base destructors run.

Johannes Schaub - litb
Doh, the slicing hadn't occurred to me at all, just the nonvirtual destructor. Nice catch.
jalf
Exactly. The compiler synthesised copy constructor is applied to init the Base object with a Derived object and of course object slicing is taking place also.
Harish H
+2  A: 

Because you create a temporary of type Derived before copy-constructing a with it. So this is basically what happens:

Derived d(); // Your temporary of type Derived is created
Base a(d); // The temporary is used to call a's copy constructor 
d.Derived::~Derived(); // The temporary is destroyed, calling both ~Derived and ~Base
a.Base::~Base(); // The nonvirtual destructor on a is called, so ~Base is called, but not ~Derived

So apart from the unnecessary copying at the beginning (which the compiler may optimize away), the actual error is that ~Base isn't virtual.

Edit Oops, completely missed the slicing that takes place as litb pointed out. Read his answer instead :)

jalf
A: 

You have one stack variable and one temporary - total of two objects constructed - so it's logical for the destructor to be called twice.

Nikolai N Fetissov
+1  A: 

Adding in the following will make the program more clear:

 Base(const Base& base){
        std::cout << "Base::Base(const Base& base)" << std::endl;
 }

The compiler will automatically create a copy constructor for you. By defining it yourself, (and by adding in the print) you can see that the number of constructors and destructors match

Base::Base()
Derived::Derived()
Base::Base(const Base& base)
Derived::~Derived()
Base::~Base()
Base::~Base()
Dolphin
A: 

1) A temporary object of Derived type is built (Derived::Derived() and Base::Base() are called)

2) The temp object is copied into "a"

3) The temporary object is destroyed ( Derived::~Derived() and Base::~Base() are called)

4) return EXIT_SUCCESS;

5) "a" is destroyed, so Base::~Base() is called

Franco