boost, shared ptr Vs weak ptr? Which to use when?

Solution 1:

In general and summary,

Strong pointers guarantee their own validity. Use them, for example, when:

  • You own the object being pointed at; you create it and destroy it
  • You do not have defined behavior if the object doesn't exist
  • You need to enforce that the object exists.

Weak pointers guarantee knowing their own validity. Use them, for example, when:

  • You access it, but it's not yours.
  • You have defined behavior if the object doesn't exist

Lock() on a weak pointer returns a strong pointer; this is how you access the weak pointer. If the object is no longer valid (it's been deleted, etc), then the strong pointer will be NULL, otherwise, it will point at the object. You will need to check this.

It's set up this way so that you cannot accidentally delete the object while you're using it, because you've made a temporary (local) strong pointer, and thus garunteed the object's existence while that strong pointer remains. When you're done using the object, you generally let the strong pointer fall out of scope (or reassigning it), which then allows the object to be deleted. For multithreading, treat them with same care you treat other things that don't have built-in thread safety, noting that the guarantee I mentioned above will hold when multithreading. AFAIK they don't do anything special past that.

The boost shared pointers also have garbage-collector like features, since when the last strong pointer to an object goes away or points somewhere else, the object gets deleted.

There's also the performance and circular dependencies mentioned in the other answers.

Fundamentally, I would say that the boost shared pointer library allows you to not mess up putting together a program, but it is no substitute for taking the time to properly design your pointers, object ownerships and lifetimes. If you have such a design, you can use the library to enforce it. If you don't have such a design, you're likely to run into different problems than before.

Solution 2:

Use weak_ptr when the objects you create contain cyclical references, i.e. shared_ptr to an object with a shared_ptr back to yourself. This is because shared_ptr cannot handle cyclical references - when both objects go out of scope, the mutual referencing means that they are not "garbage collected", so the memory is lost and you have a memory leak. Since weak_ptr does not increase the reference count, the cyclical reference problem does not occur. This also means in general that if you just want to take a pointer to something that is reference counted and do not want to increase its reference count, then use weak_ptr.

Otherwise, you can use shared_ptr.

For more information, check the Boost documentation.

Solution 3:

Shared pointers implement reference counting, weak pointers do not affect reference counting and if you don't have shared pointers to an object, only weak pointers, the object gets deleted and the weak pointers now tell you that the object has been lost.

There are two reasons to use a weak pointer:

  1. To eliminate the cost of reference count increase / decrease; however you shouldn't do this because it is error-prone and doesn't really save much time
  2. In bookkeeping data structures, e.g. you have an index of all objects Foo that are "alive", i.e. used somewhere else, and you don't want to keep a Foo alive in the index if all the "real" uses have ended. This is the basic realistic use case for weak pointers. Of course others exist also.

So in general, my recommendation would be to use weak pointers only when you know that you want to let the referenced objects be deleted and want to detect that. In other cases use shared pointers (reference counting), or direct pointers, esp. in method local variables when you know that the objects are not going to get deleted. Also errorprone, though, but faster than shared pointers.

N.B. cyclical objects do not need weak pointers, you can use non-cooked, regular pointers instead in most properly constructed programs. Weak pointers less risky, though.