Search code examples
c++c++11shared-ptrcyclic-reference

Understanding Shared_ptr with cyclic references?


I want to understand the way shared_ptr increments or decrements the reference counts?

 #include <iostream>
 #include <memory>

class B;

class A
{
  public:
  std::shared_ptr<B> b_ptr_;
};

class B
{
  public: 
  std::shared_ptr<A> a_ptr_;
};

void func(std::shared_ptr<A> &aptr)
{
  std::shared_ptr<B> bptr = std::make_shared<B>(); //Creating shared pointer
  bptr->a_ptr_ = aptr; // Creating cyclic dependency 
  aptr->b_ptr_ = bptr;

  std::cout<<"\nFunc::a_ptr_ use_count = "<<bptr->a_ptr_.use_count();
  std::cout<<"\nFunc::b_ptr_ use_count = "<<aptr->b_ptr_.use_count();     
}

int main()
{
  std::shared_ptr<A> aptr = std::make_shared<A>();
  std::cout<<"\nBefore func::a_ptr_ use_count = "<<aptr.use_count();
  func(aptr);
  std::cout<<"\nAfter func::a_ptr_ use_count = "<<aptr.use_count();
  std::cout<<"\nAfter func::b_ptr_ use_count = "<<aptr->b_ptr_.use_count();
  return 0;   
}

Output: 
This is the output I see:
Before func::a_ptr_ use_count = 1
Func::a_ptr_ use_count = 2
Func::b_ptr_ use_count = 2
After func::a_ptr_ use_count = 2
After func::b_ptr_ use_count = 1

However I was expecting this "After func::a_ptr_ use_count = 1". After bptr goes out of scope in func() the reference counts should have decremented. What am I missing here?

The question mentioned to be a duplicate does not explain about how the reference counts are incremented/decremented. I am more interested in the internal mechanics of how this is done(in shared_ptr) which is not explained in the answer of the other question attached.


Solution

  • Why should the reference count have decremented? bptr may be out of scope, but bptr only affects the reference count for your B object. There are still two references to your A object:

    1. The shared pointer still in scope in main
    2. The shared pointer stored in your B object

    As long as there is live reference to your A object, your B object continues to exist, and vice versa (that's what you triggered intentionally by making cyclic shared references). To make your B object disappear, you'd need one reference in the reference cycle to be weak/raw, and clear the pointer stored in your main method so no top-level references persist.