更新 2:此错误已在 Clang 中的 r191150 中修复。GCC 拒绝代码并显示正确的错误消息。
更新:我已经提交了一个错误报告。以下代码在我的机器上使用 clang++ 3.4 (trunk 191037)
#include <iostream>
#include <memory>
int main()
{
std::unique_ptr<int> 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<int>(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;
}
打印这个:
u_ptr.get() = 0x16fa010
*u_ptr = 42
After move
u_ptr.get() = 0x16fa010
*u_ptr = 42
s_ptr.get() = 0x16fa048
*s_ptr = 1
如您所见,unique_ptr
并没有被移走。该标准保证它在被移出后应该为空。shared_ptr
指向错误的值。
奇怪的是它编译时没有警告,valgrind 没有报告任何问题,没有泄漏,没有堆损坏。诡异的。
如果我s_ptr
使用shared_ptr
ctor 将右值 ref 设置为 aunique_ptr
而不是创建,则会显示正确的行为make_shared
:
#include <iostream>
#include <memory>
int main()
{
std::unique_ptr<int> 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<int> 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;
}
它打印:
u_ptr.get() = 0x5a06040
*u_ptr = 42
After move
u_ptr.get() = 0
s_ptr.get() = 0x5a06040
*s_ptr = 42
如您所见,u_ptr
按照标准要求移动后为空,并s_ptr
指向正确的值。这是正确的行为。
(原来的答案。)
正如 Simple 所指出的那样:“除非 Foo 有一个使用 std::unique_ptr 的构造函数,否则它不应该编译。”
稍微扩展一下:make_shared
将其参数转发给 T 的构造函数。如果 T 没有任何可以接受unique_ptr<T>&&
它是编译错误的 ctor。
但是,很容易修复此代码并获得您想要的(在线演示):
#include <memory>
using namespace std;
class widget { };
int main() {
unique_ptr<widget> uptr{new widget};
shared_ptr<widget> sptr(std::move(uptr));
}
关键是:make_shared
在这种情况下使用是错误的。shared_ptr
有一个接受 的 ctor unique_ptr<Y,Deleter>&&
,请参阅的 ctor处的 (13)shared_ptr
。