在我最近查看的一段代码中,它用 g++-4.6
编译得很好,我遇到了一个奇怪的尝试,从 std::unique_ptr
创建一个 std::shared_ptr
:
std::unique_ptr<Foo> foo...
std::make_shared<Foo>(std::move(foo));
这对我来说似乎很奇怪。这应该是 std::shared_ptr<Foo>(std::move(foo));
afaik,虽然我对动作并不完全熟悉(而且我知道 std::move
只是一个演员表,没有任何动作)。
在此 SSC(NUC*)E 上使用不同的编译器进行检查
#include <memory>
int main()
{
std::unique_ptr<int> foo(new int);
std::make_shared<int>(std::move(foo));
}
编译结果:
- g++-4.4.7 给出编译错误
- g++-4.6.4 编译没有任何错误
- g++-4.7.3 给出 内部编译器错误
- g++-4.8.1 给出编译错误
- clang++-3.2.1 编译没有任何错误
所以问题是:哪个编译器在标准方面是正确的?标准是否要求这是一个无效的声明、有效的声明或者这只是未定义的?
添加
我们已经同意其中一些编译器,例如 clang++ 和 g++-4.6.4,允许转换,而它们不应该。但是使用 g++-4.7.3(在 std::make_shared<Foo>(std::move(foo));
上产生内部编译器错误),正确拒绝 int bar(std::move(foo));
由于行为上的巨大差异,我将问题原样保留,尽管部分问题可以通过减少到 int bar(std::move(foo));
来回答。
*) NUC:不可普遍编译
原文由 stefan 发布,翻译遵循 CC BY-SA 4.0 许可协议
更新 2: 此 错误 已在 Clang 中的 r191150 中修复。 GCC 拒绝代码并显示正确的错误消息。
更新: 我已经提交了一个 错误报告。以下代码在我的机器上使用 clang++ 3.4 (trunk 191037)
打印这个:
如您所见,
unique_ptr
没有被移走。该标准 保证 它在被移出后应该为空。shared_ptr
指向错误的值。奇怪的是它编译时没有警告,valgrind 没有报告任何问题,没有泄漏,没有堆损坏。诡异的。
The proper behavior is shown if I create
s_ptr
with theshared_ptr
ctor taking an rvalue ref to aunique_ptr
instead ofmake_shared
:它打印:
如您所见,
u_ptr
按照标准要求在移动后为空,而s_ptr
指向正确的值。这是正确的行为。(原来的答案。)
正如 Simple 所指出的那样:“除非 Foo 有一个使用 std::unique_ptr 的构造函数,否则它不应该编译。”
稍微扩展一下:
make_shared
将其参数转发给 T 的构造函数。如果 T 没有任何 ctor 可以接受unique_ptr<T>&&
这是一个编译错误。但是,很容易修复此代码并获得您想要的( 在线演示):
关键是:
make_shared
在这种情况下使用是错误的。shared_ptr
有一个接受unique_ptr<Y,Deleter>&&
--- 的 ctor,参见 — 的 ctorsshared_ptr
的 (13) 。