Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using std::move with std::shared_ptr

I have a function defined as follows:

void foo(std::shared_ptr<X> x) { ... }; 

If I declare a shared ptr to X:

std::shared_ptr<X> sourcePtr(new X(...)); 

I can then call foo as follows:

foo(std::move(sourcePtr)); 

or

foo(sourcePtr); 

I understand that if I use the first option then sourcePtr becomes null. Does it also prevent the reference count from being incremented?

If that doesn't matter, which option should I prefer? Should I be considering anything else when making such a decision?

like image 549
ksl Avatar asked Apr 15 '15 07:04

ksl


People also ask

Can you move a shared_ptr?

Copying a shared_ptr involves copying its internal state object pointer and changing the reference count. Moving it only involves swapping pointers to the internal reference counter, and the owned object, so it's faster.

Does std :: move do anything?

std::move is actually just a request to move and if the type of the object has not a move constructor/assign-operator defined or generated the move operation will fall back to a copy.

Why would you choose shared_ptr instead of Unique_ptr?

In short: Use unique_ptr when you want a single pointer to an object that will be reclaimed when that single pointer is destroyed. Use shared_ptr when you want multiple pointers to the same resource.

When should you use shared_ptr?

So, we should use shared_ptr when we want to assign one raw pointer to multiple owners. // referring to the same managed object. When to use shared_ptr? Use shared_ptr if you want to share ownership of a resource.


1 Answers

Yes, if you move the shared pointer into the function, then:

  1. the original sourcePtr will become null, and

  2. the reference count does not get modified.

If you know that you will no longer need the value of sourcePtr after the function call, moving it into the function is a slight optimisation, as it saves an atomic increment (and later decrement, when sourcePtr goes out of scope).

However, be careful that the identifier sourcePtr is still valid for the rest of the scope, just that it holds a null pointer. Which means the compiler will not complain if you use it after the move, but if you forget it was moved from, you'll in all likelihood dereference the null. I tend to use this "optimising" move a lot, and I've also been bitten by it a few times: more functionality is added to the function, and if you forget to undo the move, you get a nice crash.

So moving when you no longer need it is a slight optimisation coupled with a slight maintenance burden. It's up to you to weigh which is more important in your case.

The above assumes that there is code which actually uses sourcePtr between its declaration and the final call to foo (thanks to @WhozCraig for pointing it out). If there is not, you'd be much better off creating the pointer right at the call site:

foo(std::make_shared<X>(...)); 

This way, you save the same amount of atomic operations, and you don't have a potentially dangerous empty shared pointer lying around.

like image 100
Angew is no longer proud of SO Avatar answered Sep 17 '22 14:09

Angew is no longer proud of SO