When using boost::scoped_ptr to hold a reference, the destructor of the derived object is not called. It does when using boost::shared_ptr.
#include "stdafx.h"
#include <iostream>
#include "boost/scoped_ptr.hpp"
#include "boost/shared_ptr.hpp"
using namespace std;
class Base
{
public:
Base() { cout << "Base constructor" << endl ; }
~Base() { cout << "Base destructor" << endl; }
};
class Derived : public Base
{
public:
Derived() : Base() { cout << "Derived constructor" << endl; }
~Derived() { cout << "Derived destructor" << endl; }
};
int _tmain(int argc, _TCHAR* argv[])
{
boost::scoped_ptr<Base> pb; // replacing by shared_ptr does call Derived destructor
pb.reset(new Derived());
cout << "Program ends here" << endl;
}
Can you explain this? Is there a “golden rule” not to use scoped_ptr for polymorphic member variables?
The reason why it works for
shared_ptris because it implements a special constructor and areset()method that look like this:When this constructor or
reset()is called,shared_ptr“remembers” the original typeYso that when the reference count goes to zero, it will calldeleteproperly. (Of coursepmust be convertible toT.) This is explicitly stated in the documentation:The
scoped_ptrconstructor andreset()look like this:So there’s no way for
scoped_ptrto “remember” what the original type was. And when it comes time todeletethe pointer, it essentially does this:And
scoped_ptr<T>::get()returns aT*. So ifscoped_ptrpoints to something that’s not aTbut actually a subclass ofT, you need to implement avirtualdestructor:So why doesn’t
scoped_ptrimplement a special constructor for this situation likeshared_ptrdoes? Because “scoped_ptr template is a simple solution for simple needs”.shared_ptrdoes a lot of bookkeeping to implement its extensive functionality. Note thatintrusive_ptralso doesn’t “remember” the original type of the pointer since it’s meant to be as lightweight as possible (one pointer).