From:http://www.codeproject.com/Articles/8394/Smart-Pointers-to-boost-your-code#
A few things can go wrong with smart pointers (most prominent is an invalid reference count, which deletes the object too early, or not at all). The boost implementation promotes safety, making all "potentially dangerous" operations explicit. So, with a few rules to remember, you are safe.
There are a few rules you should (or must) follow, though:
Rule 1: Assign and keep - Assign a newly constructed instance to a smart pointer immediately, and then keep it there. The smart pointer(s) now own the object, you must not delete it manually, nor can you take it away again. This helps to not accidentally delete an object that is still referenced by a smart pointer, or end up with an invalid reference count.
Rule 2: a _ptr<T>
is not a T *
- more correctly, there are no implicit conversions between a T *
and a smart pointer to type T
.
This means:
- When creating a smart pointer, you explicitly have to write
..._ptr<T> myPtr(new T)
- You cannot assign a
T *
to a smart pointer - You cannot even write
ptr=NULL
. Useptr.reset()
for that. - To retrieve the raw pointer, use
ptr.get()
. Of course, you must not delete this pointer, or use it after the smart pointer it comes from is destroyed, reset or reassigned. Useget()
only when you have to pass the pointer to a function that expects a raw pointer. - You cannot pass a
T *
to a function that expects a_ptr<T>
directly. You have to construct a smart pointer explicitly, which also makes it clear that you transfer ownership of the raw pointer to the smart pointer. (See also Rule 3.) - There is no generic way to find the smart pointer that "holds" a given raw pointer. However, the boost: smart pointer programming techniques illustrate solutions for many common cases.
Rule 2: No circular references - If you have two objects referencing each other through a reference counting pointer, they are never deleted. boost provides weak_ptr
to break such cycles (see below).
Rule 3: no temporary shared_ptr - Do not construct temporary shared_ptr
to pass them to functions, always use a named (local) variable. (This makes your code safe in case of exceptions. See the boost: shared_ptr best practices for a detailed explanation.)
Cyclic References
Reference counting is a convenient resource management mechanism, it has one fundamental drawback though: cyclic references are not freed automatically, and are hard to detect by the computer. The simplest example is this:
struct CDad;
struct CChild;
typedef boost::shared_ptr<CDad> CDadPtr;
typedef boost::shared_ptr<CChild> CChildPtr;
struct CDad : public CSample
{
CChildPtr myBoy;
};
struct CChild : public CSample
{
CDadPtr myDad;
};
// a "thing" that holds a smart pointer to another "thing":
CDadPtr parent(new CDadPtr);
CChildPtr child(new CChildPtr);
// deliberately create a circular reference:
parent->myBoy = child;
child->myDad = dad;
// resetting one ptr...
child.reset();