C++11: How to create cyclic dependencies with shared_ptr and how to avoid them

C++ smart pointers are god send to C++ programmers. It avoids dealing with raw pointers and takes care of resource deallocation when the pointed “whatever” goes out of scope. All great. But there does exist some pitfalls and we should be vary of them. One such pitfalls is cyclic dependency when using shared_ptr. Cyclic dependency occurs when there is self-reference either in its own member or through the member of a member or through the member of a member of a member…. ok. I will stop. You get it :P.

Cyclic dependency

Cyclic dependency

Creating cyclic dependency

First we will see how we can create a cyclic dependency. Then we will see how to avoid them by using weak pointers.

Here we show two ways to create cyclic dependency:

  1. Cyclic dependency due to a self-referencing member
  2. Cyclic dependency due to a member of a member referencing this

Case 1

When ptr is created, its count is initialised to 1. When it is assigned to ptr->a, its count is incremented by 1 to 2. What this means is that ptr will not be deleted until both ptr and ptr->a are reset. But there is no way for that to happen. When ptr goes out of scope, the count will be decremented by 1 to 1. Since the count is not 0, ptr will not be deleted. ptr->x will not be reset until ptr is deleted. ptr will not be deleted until ptr->x is reset.
So shortly: ptr cannot be released because ptr->x will not be reset until ptr is reset.

Case 2

When x is created, its count is initialised to 1. When it is assigned to x->b->a, its count is incremented by 1 to 2. What this means is that x will not be deleted until both x and x->b->a are reset. But there is no way for that to happen. When x goes out of scope, the count will be decremented by 1 to 1. Since the count is not 0, x will not be deleted. Since x is not deleted, x->b will be not be deleted. Since x->b will not be deleted, x->b->a will not be deleted. If x->b->a will not be deleted, x will not be deleted. Go back 3 lines and start reading again and again and again :P.
So shortly: x(and hence x->b) will not be released because x->b->a will not be reset until x is reset.

Solving cyclic dependency using weak_ptr

Changing the self-referencing member a of ClassA to weak_ptr fixes the cyclic dependency problem in case 1.
Changing the member a of ClassB to weak_ptr fixes the cyclic dependency problem in case 2.

Courtesy: Stackoverflow