Here are some things I learned about smart pointers which no one seems to have written up yet.
The java world has far better documentation than the C++ world. There are some cases when you pile frame-works on top of each other that the java world struggles, but even basic language issues seem to be sparsely discussed. I’ve actually found myself enjoying memory management and RAII, with the exception of the Windows
CComPtr. Here’s are some things I’ve learned about smart pointers, and conjectures on how to use them properly.
boost::scoped_ptr— This is meant for allocating and freeing an object strictly in a scope. The “responsibility” of the object is strictly within that scope. Scoped pointers cannot be assigned, and should only be passed around as references to objects with a smaller lifecycle than the scope.
std::auto_ptr— These are meant for use “like an automatic variable”, but will pass on any responsibility. These should not be used directly, rather should be used as parameters or return values. When, say, a factory is creating an object which the caller is responsible for, or you need an object as a parameter which you will clean up, use an
boost::shared_ptr— These imply a shared responsibility. These should be used when multiple objects may use an object over a lifetime which is unclear (or at least, not predicated on a particular scope). In a multi-threaded application, shared pointers could be used to share data objects or messages around. Shared pointers should only be assigned to other shared pointers, or perhaps references; nothing else.
boost::intrusive_ptr— This lets the class know that there’s a smart pointer pointing to it. This may be necessary sometimes, but it has the stench of sulphur about it. I’ll stay away until I need to know more.
CComPtr— This was probably actually forged in hell. I don’t know what possible point this thing has, only that it’s incredibly dangerous to use. A
CComPtrshould only be assigned to another
CComPtr(but see the notes). It could also be assigned to a reference.
CComPtris intrusive. Objects know about how many other objects are pointing to them. Worse, by definition the initial reference count for a new object is 1.
CComPtris assignable. When you assign either a new object / pointer to a
CComPtr, the reference count goes up, so
CComPtr item = new Item()will result in item not getting cleaned up at the end of scope.
CComPtr item(new Item()), the item will not be cleaned up at the end of the method. The correct way to assign a new object to a
CComPtr item; item.Attach(new Item());.
&item) returns a raw pointer, not the address of the
CComPtr. While in this “mode”, the
CComPtrwill be updated with whatever’s in the raw pointer, but no reference incrementing or freeing will occur. So
*(&ccp1) = ccp2(where both ccp1 and ccp2 are
CComPtrs) will result in the object being freed twice at the end of scope. Worse, this is the default way you grab objects from Windows.
CAdapttemplate class which you wrap your
CComPtrsin. That is, if you want a
CComPtr, you need to write
std::vector< CAdapt<CComPtr> >. Unbelievable.
1 I’m joking, there is no God. I just man the fuck up and take care of it.