Foo(Foo&& other) {
this->bar = other.bar;
other.bar = nullptr;
}
Foo(Foo* other) {
this->bar = other->bar;
other->bar = nullptr;
}
以上两个似乎只是在做同样的事情。那么为什么建议使用移动构造函数呢?它提供了哪些优势?
答案 0 :(得分:4)
使用正确的移动构造函数的原因很多:
公约。请考虑以下代码:
Foo foo;
Foo bar(std::move(foo));
如果您看到该代码,那么 清楚了解您要尝试做的事情:您将foo
移动到bar
。相比之下:
Foo foo;
Foo bar(&foo);
这是什么意思?它是否存储指向另一个Foo
的指针? Foo
是某种链表节点类型吗?您必须在Foo
基于指针的构造函数的文档中查找。
您无法获得指向prvalues的指针。 Foo bar(Foo{})
会(在C ++之前的17版本)创建一个临时值prvalue然后从它移动到bar
(移动可以在C ++之前被省略17)。但是你不能这样做:Foo bar(&Foo{})
。
您可以从有意义的事物中自动移动。 C ++ 17的广义省略使许多这些自动移动消失了,但还有一些仍然存在:
Foo function()
{
Foo foo;
//Do stuff
return foo;
}
这将从foo
移出而无需致电std::move
。原因是foo
是一个即将被销毁的局部变量。以这种方式返回它意味着从它移动到返回值是完全合理的。
您的方式需要明确撰写return &foo
。而auto
返回类型推导使事情变得相当困难。这样的函数会推导出Foo*
,这意味着你只是返回了一个悬空指针。如果你做return foo;
,它会推导Foo
prvalue,并自动移动(可能会被省略)。
无需nullptr
次检查。如果您使用Foo*
,则可能会有人传递空指针。虽然有参考,但它更不可能(并且他们已经调用了UB)。
如果我们想要使用现有语言结构移动支持,我们只使用非const
引用来表示"移动"而不是指针。通过赋予它自己的语法,在我们移动某些东西时以及当我们不移动时明确说明。