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 tofuncwhich steals ownership ofptrbefore the function is called.funcis 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).std::shared_ptr<int>, so a temporary object is constructed in the first case when condition is hit, check godbolt.org/z/44EM6YPad