9

I was trying with the cyclic references for boost::shared_ptr, and devised following sample:

class A{ // Trivial class
public:
    i32 i;
    A(){}
    A(i32 a):i(a){}
    ~A(){
        cout<<"~A : "<<i<<endl;
    }
};

shared_ptr<A> changeI(shared_ptr<A> s){
    s->i++;
    cout<<s.use_count()<<'\n';

    return s;
}

int main() {

    shared_ptr<A> p1 = make_shared<A>(3);
    shared_ptr<A> p2 = p1;
    shared_ptr<A> p3 = p2;
    shared_ptr<A> p4 = p3;

    p1 = p4; // 1) 1st cyclic ref.
    cout<<p1.use_count()<<'\n';

    p1 = changeI(p4); // 2) 2nd cyclic ref.

    cout<<p1.use_count()<<'\n';

//  putchar('\n');
    cout<<endl;
}

which outputs

4
5
4

~A : 4

Is it that I've misinterpreted the cyclic references mentioned for boost::shared_ptr? Because, I expected different output thinking of indirect references to p1 after comments 1) and 2). So this code doesn't require boost::weak_ptr! So what are the cyclic references where weak_ptrs would be required?

Thanks in advance.

ltjax
  • 15,837
  • 3
  • 39
  • 62
zeropoint
  • 235
  • 1
  • 4
  • 10
  • 1
    the middle result of 5 is due to passing shared pointer object by value to function leading to new copy of shared pointer as s – ahmed allam Dec 27 '19 at 11:58

2 Answers2

24

Yes, you have misinterpreted this. In your example, all the pointers are pointing to the same object, not forming any cycles.

The assignment of p4 to p2 is a no-op, since those pointers were already equal to begin with.

Here's an example with real cyclic references, maybe that will clear things up:

struct A
{
  std::shared_ptr<A> ptr;
};

void main()
{
  std::shared_ptr<A> x=std::make_shared<A>();
  std::shared_ptr<A> y=std::make_shared<A>();

  x->ptr = y; // not quite a cycle yet
  y->ptr = x; // now we got a cycle x keeps y alive and y keeps x alive
}

You can even make this even simpler:

void main()
{
  std::shared_ptr<A> x=std::make_shared<A>();

  x->ptr = x; // never die! x keeps itself alive
}

In both examples, the objects in the shared_ptrs are never destructed, even after you leave main.

ltjax
  • 15,837
  • 3
  • 39
  • 62
  • Thank you for clarification. Now in your example, will `x` die when process ends (in Linux - I am using Ubuntu 10.04), or it depends on OS whether it lives till reboot? – zeropoint Sep 09 '12 at 12:44
  • 2
    Yes, strictly speaking that's the OS's job. All the OSs I know do it though. Some embedded OSs might not. – ltjax Sep 09 '12 at 13:21
  • Ok, so cycles would be formed when some object having a member pointer is directly/indirectly pointing to itself. Are there any other scenarios? Please do tell. – zeropoint Sep 10 '12 at 05:01
  • 3
    No, that's pretty much the definition of a cycle; an object pointing directly or indirectly to itself, thus never losing that one reference. – ltjax Sep 10 '12 at 09:12
  • 1
    Will the use_count() of x and y decrease from 2 to 1 when main returns? – Moshe Rabaev Jun 27 '16 at 20:13
  • @Itjax is'nt `ptr` will get destruct while calling destructor of `A` so it will decrease reference count to 0 and it will get free. Please clear my confusion. – EmptyData Jun 27 '17 at 08:50
  • @EmptyData The destructor is only called once the reference count is already 0. – ltjax Jul 09 '17 at 19:38
2

Just wanted to point out: the reason why the second line of the output is a 5 and not a 4 is not because of the s->i++ increase, but because the shared_ptr<A> s parameter is being passed by value.

Upon calling

p1 = changeI(p4); // 2) 2nd cyclic ref.

p4 will be copied to yet another shared_pointer, temporarily increasing the use_count by one during the scope of the function.

Maybe I'm playing captain obvious here (;

levelont
  • 584
  • 4
  • 12