I was always assuming that std::move()
on a std::shared_ptr
steals the pointer and sets the pointer of the original to nullptr
-thus not increasing the reference count. That does not seem to be true in my world.
SETUP:
MacOS, g++ -version => "Apple LLVM version 10.0.1 (clang-1001.0.46.3)"
CODE:
#include <cstdio> #include <memory> class Thing { public: Thing(int N) : value(N) {} int value; }; void print(const char* name, std::shared_ptr<Thing>& sp) { printf("%s: { use_count=%i; }\n", name, (int)sp.use_count()); } int main(int argc, char** argv) { std::shared_ptr<Thing> x(new Thing(4711)); print("BEFORE x", x); std::shared_ptr<Thing> y = std::move(x); y->value = 4712; print(" AFTER x", x); print(" AFTER y", y); return 0; }
OUTPUT:
Compiling (g++ tmp.cpp -o test
), and running (./test
), delivers
BEFORE x: { use_count=1; } AFTER x: { use_count=2; } AFTER y: { use_count=2; }
So, the reference count is increased while using std::move()
.
QUESTION:
What is going on, here?
By moving the shared_ptr instead of copying it, we "steal" the atomic reference count and we nullify the other shared_ptr . "stealing" the reference count is not atomic, and it is hundred times faster than copying the shared_ptr (and causing atomic reference increment or decrement).
std::move. std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object. In particular, std::move produces an xvalue expression that identifies its argument t . It is exactly equivalent to a static_cast to an rvalue reference type.
std::shared_ptr::getReturns the stored pointer. The stored pointer points to the object the shared_ptr object dereferences to, which is generally the same as its owned pointer.
In C++11, std::move is a standard library function that casts (using static_cast) its argument into an r-value reference, so that move semantics can be invoked. Thus, we can use std::move to cast an l-value into a type that will prefer being moved over being copied.
What is going on, here?
On MacOS, it seems that you must explicitly enable move-sematics with -std=c++11
(or later standards)¹. Otherwise, the example happens to compile (i.e., std::shared_ptr
from the related library implementation is usable) but doesn't work correctly as the required language features aren't enabled. This results in actual copies being made instead of move constructions. It would have been better if the AppleClang package didn't even allow an instantiation of std::shared_ptr
when the required language features isn't enabled.
¹) Thanks to @t.niese for testing the given compiler/platform.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With