When trying to use an auto_ptr
with a type that was declared with forward-declaration, like this:
class A;
...
std::auto_ptr<A> a;
the destructor of A
is not called (apparently, because auto_ptr
internally delete
s the underlying pointer and the destructor for an incomplete type cannot be called).
However, the same code works fine and the destructor is called when using std::shared_ptr
instead of std::auto_ptr
.
How can that be explained?
A
shared_ptr
can be declared with an incomplete type, yes. The type does not need to be complete until you initialize or reset it.When you initialize or reset a
shared_ptr
to point to a new object, it creates a "deleter" that can be used to destroy the object. For example, consider the following:When you call
reset
,A
is complete because you're creating an instance of it usingnew
. Thereset
function creates and stores internally a deleter that will be used to destroy the object usingdelete
. BecauseA
is complete here, thatdelete
will do the right thing.By doing this,
shared_ptr
does not require thatA
be complete when theshared_ptr<A>
is declared; it only requires thatA
is complete when theshared_ptr
constructor that takes a raw pointer is invoked or when you callreset
with a raw pointer.Note that if
A
is not complete when you do one of those two things,shared_ptr
won't do the right thing and the behavior is undefined (this is explained in the documentation forboost::shared_ptr
, which is probably the best resource for learning how to useshared_ptr
correctly, regardless which version ofshared_ptr
you are using (Boost, TR1, C++0x, etc.)).However, as long as you always follow the best usage practices for
shared_ptr
--notably, if you always initialize and reset ashared_ptr
directly with a pointer resulting from a call tonew
--you won't have to worry about violating this rule.This functionality isn't free:
shared_ptr
has to create and store a pointer to the deleter functor; typically this is done by storing the deleter as part of the block that stores the strong and weak reference counts or by having a pointer as part of that block that points to the deleter (since you can provide your own deleter).auto_ptr
(andunique_ptr
too) is designed to be free of any overhead: operations on it are supposed to be just as efficient as using a dumb pointer. Thus,auto_ptr
doesn't have this functionality.