What is the cyclic dependency issue with shared_ptr?

The problem isn’t that complex. Let --> represent a shared pointer:

The rest of the program  --> object A --> object B
                                    ^     |
                                     \    |
                                      \   v
                                        object C

So we’ve got ourselves a circular dependency with shared pointers. What’s the reference count of each object?

A:  2
B:  1
C:  1

Now suppose the rest of the program (or at any rate the part of it that holds a shared pointer to A) is destroyed. Then the refcount of A is reduced by 1, so the reference count of each object in the cycle is 1. So what gets deleted? Nothing. But what do we want to be deleted? Everything, because none of our objects can be reached from the rest of the program any more.

So the fix in this case is to change the link from C to A into a weak pointer. A weak pointer doesn’t affect the reference count of its target, which means that when the rest of the program releases A, its refcount hits 0. So it’s deleted, hence so is B, hence so is C.

Before the rest of the program releases A, though, C can access A whenever it likes by locking the weak pointer. This promotes it to a shared pointer (and increases the refcount of A to 2) for as long as C is actively doing stuff with A. That means if A is otherwise released while this is going on then its refcount only falls to 1. The code in C that uses A doesn’t crash, and A is deleted whenever that short-term shared pointer is destroyed. Which is at the end of the block of code that locked the weak pointer.

In general, deciding where to put the weak pointers might be complex. You need some kind of asymmetry among the objects in the cycle in order to choose the place to break it. In this case we know that A is the object referred to by the rest of the program, so we know that the place to break the cycle is whatever points to A.

Leave a Comment