I was working on some C++ code using std::move
on shared_ptr
and got really weird output. I've simplified my code as below
int func(std::shared_ptr<int>&& a) {
return 0;
}
int main() {
std::shared_ptr<int> ptr = std::make_shared<int>(1);
for (int i = 0; i != 10; ++i) {
func(i == 9 ? std::move(ptr) : std::shared_ptr<int>(ptr));
}
if (ptr) {
std::cout << "ptr is not null: " << *ptr << "\n";
} else {
std::cout << "ptr is null\n";
}
return 0;
}
And I got output
ptr is null
As I expected, my ptr
will be moved (cast to std::shared_ptr<int>&&
) at last loop, and since func
never steals memory in a
, my ptr
outside will be non-null (which turns out to be null actually). And if I replace
func(i == 9 ? std::move(ptr) : std::shared_ptr<int>(ptr));
with if-else statement
if (i == 9) func(std::move(ptr));
else func(std::shared_ptr<int>(ptr));
the output will be
ptr is not null: 1
I am so confused about this behavior of compiler.
I've tried GCC and clang with different std version and optimization level, and got same output. Could someone explain for me why and where the data under ptr
was stolen ?
std::shared_ptr<int>
so in the first case a move constructed temporary instance is constructed and passed tofunc
which steals ownership ofptr
before the function is called. – Surprisingfunc
is a reference. Only the reference's lifetime enda at the end offunc
, not the referred object (unless the reference happens to be extending the lifetime of a materialized temporary object). – Surprisingstd::shared_ptr<int>
, so a temporary object is constructed in the first case when condition is hit, check godbolt.org/z/44EM6YPad – Hyades