views:

42

answers:

1

Was trying to find the best way to use ptr_vector to store, access and release objects, especially when the stored object is inherited from other (ptr_vector should not have any issues with object slicing). But when running the below program, surprisingly the derived class isn't being destructed. Anyone know why?

#include <boost/ptr_container/ptr_vector.hpp>
#include <iostream>
#include <boost/ptr_container/ptr_map.hpp>
#include <boost/foreach.hpp>
using namespace std;

class A
{
 public:
 int id;
 A() {cout<<"Constructed A()"<<endl;}
 A(int i):id(i) {cout<<"Constructed A"<<i<<endl;}
 ~A() {cout<<"* Destructed A"<<id<<endl;}
};
class B:public A
{
 public:
 int i;
 B() {cout<<"Constructed B"<<endl;}
 B(int ii):i(ii) {id=ii;cout<<"Constructed B"<<i<<endl;}
 ~B() {cout<<"* Destructed B"<<i<<endl;}
};

class zoo
{
 boost::ptr_vector<A> the_animals;
public:
 void addAnimal(A* a) {the_animals.push_back( a );}
 void removeAnimal(int id) {the_animals.release(the_animals.begin()+id); }
 void removeOwnership(int id) {the_animals.release(the_animals.begin()+id).release();}
};

int main()
{
 zoo z;
 z.addAnimal( new B(0) );
 //delete abc;z.addAnimal(abc);//doing this will cause heap corruption
 B* lion=new B(1);
 z.addAnimal(lion);
 z.removeOwnership(1);
        delete lion;
 z.removeAnimal(0);
}//main

The output for the program is:

Constructed A()
Constructed B0
Constructed A()
Constructed B1
* Destructed B1
* Destructed A1
* Destructed A0

Why isn't B0 being destructed? Did the object get sliced?

+8  A: 

The destructor of the base class is not virtual:

 ~A() {cout<<"* Destructed A"<<id<<endl;}

Should be:

 virtual ~A() {cout<<"* Destructed A"<<id<<endl;}

Why ? See When should your destructor be virtual?

Samuel_xL
But I'm not using virtual functions at all. Why should the destructor be virtual?
Nav
@Nav, see http://stackoverflow.com/questions/1123044/when-should-your-destructor-be-virtual for a more detailed answer, but basically if you delete an object through a pointer to it's base type your base objects destructor must be virtual
Glen
@Glen thanks, I've included the link in the answer.
Samuel_xL
Oh god! I completely missed the point that B was being upcasted. Thanks Samuel and Glen :)
Nav
B isn't being upcasted. This is a very simple case of polymorphism - you're calling a function (destructor) on a pointer of type pointer to base class A. Without that function being virtual, it doesn't know it needs to check the virtual function table and call the overriden destructor in B.
Andy Dent