Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copy boost::shared_ptr

typedef boost::shared_ptr<SomeData> data_ptr;
data_ptr cached_ptr;   // class member 
bool someWork(data_ptr& passed_ptr)
{
  // must copy passed_ptr = cached_ptr under some conditions
  // without pointing at the same memory 
  // I saw somewhere that I should do 
  // passed_ptr.reset(new SomeData(???))
  // I don't have a "reset" on passed_ptr
}

I looked at documentation;

copy and converting constructors

shared_ptr(shared_ptr const & r); // never throws
template<class Y> shared_ptr(shared_ptr<Y> const & r); // never throws
Requires: Y* should be convertible to T*.

Effects: If r is empty, constructs an empty shared_ptr; otherwise,
         constructs a shared_ptr that shares ownership with r.

I don't know how that works - is it like this ?

passed_ptr = shared_ptr(cached_ptr);

? Where would the const go ? And what does it mean that they share ownership ? Then it is not a copy, if I modify "passed_ptr", the change will affect "cached_ptr" ?

I can't find examples... Please help.

Thank you.

like image 541
Thalia Avatar asked May 07 '13 16:05

Thalia


2 Answers

Well, if you have a shared_ptr and you assign it to another shared_ptr, those two shared pointers will share ownership of the object - meaning the reference counting for the pointed object 's ownership will be increased by one.

In fact, in the above line, you do not need to construct a temporary shared pointer at all. This is enough:

passed_ptr = cached_ptr;

Anyway, copy-constructing a shared_ptr basically follows the same logic: you start with a shared pointer, and you end up with two shared pointers that co-own the same object (meaning that the object will be destroyed only when both of those shared pointers get destroyed). So when you do this:

passed_ptr = shared_ptr(cached_ptr);

You actually start with one shared pointer (cached_ptr) to a given object, then create a temporary one (that brings the reference count to 2) which gets in turn assigned to passed_ptr (bringing the reference count to 3), and eventually gets destroyed (bringing the reference count back to 2).

On the other hand, if what you want is to have passed_ptr as a shared pointer to a copy of the object being pointed to by cached_ptr, then you should rather do (supposing Data is copyable, of course):

passed_ptr = boost::make_shared<Data>(*cached_ptr);

Or, alternatively:

passed_ptr.reset(new Data(*cached_ptr));
like image 110
Andy Prowl Avatar answered Oct 11 '22 15:10

Andy Prowl


Okay. Let's see if we can talk about this.

std::shared_ptr<Data> x = std::make_shared<Data>();
std::shared_ptr<Data> y = x;

assert(x.get() == y.get());

If I change something about what x points to, that would change information about y as well. Because they point to the same thing.

x->member = 3;
assert(x->member == 3);
assert(y->member == 3);

I can change what x points to without changing what y points to.

x = std::make_shared<Data>();
assert(x.get() != y.get());

If I do this, then changes to x are not reflected to in y. Because they point to different things.

x->member = 4;
assert(x->member == 4);
assert(y->member != 4);

If I want to make a copy of the contents of x, and store that in y, then I need to create a new shared object.

y = std::make_shared<Data>(*x);

At this point, both x and y have that member variable set to 4. Because x had it set, and we created *y with the contents of *x.

assert(x->member == 4);
assert(y->member == 4);

But, because x and y are pointing to different things in memory, we can change one of them.

assert(x.get() != y.get();
x->member = 3;
assert(x->member == 3);
assert(y->member == 4);

If I was to pass a shared_ptr to a function, then it's just like the first case.

void func(std::shared_ptr<Data> z) {
    assert(x.get() == z.get());
}

func(x);

I can also release the contents of a particular shared_ptr by using reset(). This will cause the value that the shared_ptr is pointing at to become NULL.

x.reset();
assert(x.get() == NULL);

With regards to const correctness, it's a bit weird.

const std::shared_ptr<Data> x;
x.reset(); // Fails because the shared_ptr is const.
x->member = 3; // Succeeds because Data is not const.

std::shared_ptr<const Data> x;
x.reset(); // Succeeds because the shared_ptr is not const.
x->member = 3; // Fails because Data is const.
like image 41
Bill Lynch Avatar answered Oct 11 '22 13:10

Bill Lynch