0

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.

red_dragon
  • 13
  • 2

1 Answers1

1

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.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • When the bptr in func() goes out of scope, shouldn't reference count for a_ptr_ in Class B be decremented by 1? – red_dragon Jun 13 '17 at 00:59
  • 1
    @red_dragon: The `B` object still exists. Reference counts aren't transitive; if 10,000 references exist to a `B` object, and said `B` object references an `A` object, then `A` gets a single reference from that. It doesn't matter than the reference count to `B` object went down so long as `B` object still exists. Since the `B` object is still referenced by the `A` object, it will never die (barring explicitly clearing `A`'s reference to it), so `A` object's reference count will never go down. – ShadowRanger Jun 13 '17 at 01:39
  • Thanks for your comments. – red_dragon Jun 13 '17 at 01:57
  • 1
    Thanks for your comments. Can you please clarify the following in my example - once bptr in func() goes out of scope, the reference count of bptr is alone decremented but the reference count for a_ptr remains 2 because the memory of bptr still remains and it is still referring aptr. It is true that if a memory for an object is not deallocated then all references to the shared pointers within that object still remains even if that object variable goes out of scope. – red_dragon Jun 13 '17 at 02:03
  • 2
    Yup. As long as a single shared pointer to an object exists, the object exists, and it will not destroy its own shared pointers (or any other resource). Your problem is thinking of the object going out of scope. It didn't. It was never in scope. The shared pointer `bptr` was in scope, and it was destroyed when it went out of scope, but another shared pointer to the same object was created before that happened, so the object itself remained alive. – ShadowRanger Jun 13 '17 at 02:06
  • Awesome!!. This explains it. Thanks. – red_dragon Jun 13 '17 at 02:09