Dean Li
Dean Li

Reputation: 3

Shared_ptr instance is not set for an object as expected

I have a struct A which has a member another struct C. So A with c1Ptr_ as member. I use 2 structs S and N. N has as member A, a_ and S has as member C, c_. After I instantiated A and create for S a c object using the created A object and I pass the created A object to N I would expect to have the A->c1Ptr_ in N as well.
Thank you.

 #include <iostream>
    #include <memory>
    using namespace std;
    
    
    
    struct C1 
    {
        C1(int x):x_(x)
        {
            std::cout<<"-C1: x_: " << x_ << std::endl;
        }
        int x_;
        ~C1()
        {
            std::cout<<"-DC1: x_: " << x_ << std::endl;
        }
    };
    
    using C1ptr = std::shared_ptr<C1>;
    
    
    
    struct A
    {
       C1ptr c1Ptr;
    };
    
    
    struct S
    {
       S(C1ptr& c1Ptr):c1Ptr_(c1Ptr)
       {
           
       }
       
       C1ptr c1Ptr_;
    };
    
    struct N
    { 
        N(std::shared_ptr<A> a):a_(a)
        {
            
        }
        std::shared_ptr<A> a_;
    };
    
    
    
    int main()
    {
       std::shared_ptr<A> a = std::make_shared<A>();
       S s(a->c1Ptr);
       N n(a);
       
       s.c1Ptr_ = std::make_shared<C1>(12);
       
       if (n.a_->c1Ptr)
       {
           std::cout<<"c1Ptr is set for N\n";
       }
       else
       {
           std::cout<<"c1Ptr is NOT set for N\n"; // why c1Ptr is not set for n.a_ ? 
       }
    
        return 0;
    }

Upvotes: 0

Views: 156

Answers (2)

rturrado
rturrado

Reputation: 8074

You can try to work this out on your own by drawing the objects a, s, and n and their contents, and what their contents point to:

auto a = std::make_shared<A>();  // a(c1Ptr_ = null)
S s(a->c1Ptr_);                  // a(c1Ptr_ = null), s(c1Ptr_ = null)
N n(a);                          // a(c1Ptr_ = null), s(c1Ptr_ = null), n(a_ = a)
                                 // [n.a_ points to a]

After this initial block of instructions:

  • a and s have their shared pointer members c1Ptr_ with a value of nullptr.
  • n has its shared pointer member a_ pointing to the object a.
s.c1Ptr_ = std::make_shared<C1>(12);  // (1) a(c1Ptr_ = null), s(c1Ptr_->x_ = 12 ), n(a_ = a) 
                                      //     [and you modify s]
if (n.a_->c1Ptr_) {
    std::cout << "c1Ptr is set for N\n\n";
}
else {
    std::cout << "c1Ptr is NOT set for N\n\n";  // (1)
}

Here:

  • you just modify s.c1Ptr_, but that doesn't affect a, and ultimately, n.
  • s.c1Ptr_ was originally set to point to the same C1 object as a.c1Ptr_ (actually, nullptr); now you're just making it point to something else.
a->c1Ptr_ = std::make_shared<C1>(15);  // (2) a(c1Ptr_->x_ = 15 ), s(c1Ptr_->x_ = 12 ), n(a_ = a)
                                       //     [and you modify a]
if (n.a_->c1Ptr_) {
    std::cout << "c1Ptr is set for N\n\n";  // (2)
}
else {
    std::cout << "c1Ptr is NOT set for N\n\n";
}

What would have happened if you had changed a->c1Ptr_ instead? Since n->a_ points to a and we are modifying a, n->a_->c1Ptr_ is also set.

[Demo]

Upvotes: 0

Sorin
Sorin

Reputation: 11968

shared_ptr doesn't share a pointer, it shares ownership of a pointer.

This means that you can change individual shared_ptr to point to other things, indepnendent of other shared_ptr's, but as soon as there's no shared_ptr pointing at something, that something get's deleted. Think of it as adding a counter to the pointer. When you create, delete or reassign a shared_ptr to something other than nullptr, you will increment or decrement the counter. If the counter reaches 0 (usually on a delete) then it also deletes the pointer.

In your case you are copying a nullptr from a. So you have two shared_ptr both storing nullptr. Then you change one of them to point to a new thing (12). This won't change anything else in memory, or specifically the value of other shared_ptrs.

Upvotes: 1

Related Questions