In a piece of code I reviewed lately, which compiled fine with g++-4.6, I encountered a strange try to create a std::shared_ptr from std::unique_
UPDATE 2: This bug has been fixed in Clang in r191150. GCC rejects the code with a proper error message.
UPDATE: I have submitted a bug report. The following code on my machine with clang++ 3.4 (trunk 191037)
#include
#include
int main()
{
std::unique_ptr u_ptr(new int(42));
std::cout << " u_ptr.get() = " << u_ptr.get() << std::endl;
std::cout << "*u_ptr = " << *u_ptr << std::endl;
auto s_ptr = std::make_shared(std::move(u_ptr));
std::cout << "After move" << std::endl;
std::cout << " u_ptr.get() = " << u_ptr.get() << std::endl;
std::cout << "*u_ptr = " << *u_ptr << std::endl;
std::cout << " s_ptr.get() = " << s_ptr.get() << std::endl;
std::cout << "*s_ptr = " << *s_ptr << std::endl;
}
prints this:
u_ptr.get() = 0x16fa010
*u_ptr = 42
After move
u_ptr.get() = 0x16fa010
*u_ptr = 42
s_ptr.get() = 0x16fa048
*s_ptr = 1
As you can see, the unique_ptr hasn't been moved from. The standard guarantees that it should be null after it has been moved from. The shared_ptr points to a wrong value.
The weird thing is that it compiles without a warning and valgrind doesn't report any issues, no leak, no heap corruption. Weird.
The proper behavior is shown if I create s_ptr with the shared_ptr ctor taking an rvalue ref to a unique_ptr instead of make_shared:
#include
#include
int main()
{
std::unique_ptr u_ptr(new int(42));
std::cout << " u_ptr.get() = " << u_ptr.get() << std::endl;
std::cout << "*u_ptr = " << *u_ptr << std::endl;
std::shared_ptr s_ptr{std::move(u_ptr)};
std::cout << "After move" << std::endl;
std::cout << " u_ptr.get() = " << u_ptr.get() << std::endl;
//std::cout << "*u_ptr = " << *u_ptr << std::endl; // <-- would give a segfault
std::cout << " s_ptr.get() = " << s_ptr.get() << std::endl;
std::cout << "*s_ptr = " << *s_ptr << std::endl;
}
It prints:
u_ptr.get() = 0x5a06040
*u_ptr = 42
After move
u_ptr.get() = 0
s_ptr.get() = 0x5a06040
*s_ptr = 42
As you see, u_ptr is null after the move as required by the standard and s_ptr points to the correct value. This is the correct behavior.
(The original answer.)
As Simple has pointed out: "Unless Foo has a constructor that takes a std::unique_ptr it shouldn't compile."
To expand on it a little bit: make_shared forwards its arguments to T's constructor. If T doesn't have any ctor that could accept that unique_ptr it is a compile error.
However, it is easy to fix this code and get what you want (online demo):
#include
using namespace std;
class widget { };
int main() {
unique_ptr uptr{new widget};
shared_ptr sptr(std::move(uptr));
}
The point is: make_shared is the wrong thing to use in this situation. shared_ptr has a ctor that accepts an unique_ptr, see (13) at the ctors of shared_ptr.