Rvalue参考:为什么rvalues没有隐式移动?

时间:2013-01-16 05:00:38

标签: c++ c++11 rvalue-reference

关于C ++右值引用(http://www.artima.com/cppsource/rvalue.html)的关于Artima的文章,有一些词:这就是为什么在传递给基类时有必要说move(x)而不是x。这是移动语义的一个关键安全功能,旨在防止意外地从某个命名变量移动两次。

当这样的双重动作可以执行时,我无法想到这种情况。你能举个例子吗?换句话说,如果T&&的所有成员都是右值引用而不仅仅是引用,会出现什么问题?

2 个答案:

答案 0 :(得分:16)

考虑这种情况:

void foo(std::string x) {}
void bar(std::string y) {}

void test(std::string&& str)
{
    // to be determined
}

我们希望foo使用str,然后bar使用str,两者都具有相同的值。最好的方法是:

foo(str); // copy str to x
bar(std::move(str)); // move str to y; we move it because we're done with it

这样做是错误的:

foo(std::move(str)); // move str to x
bar(std::move(str)); // move str to y...er, except now it's empty

因为在第一次移动后,str的值未指定。

因此在rvalue引用的设计中,这种隐式移动并不存在。如果是这样,我们上面的最佳方式就行不通,因为第一次提到str会改为std::move(str)

答案 1 :(得分:3)

我看到它的方式是,如果我们有一些右值参考x:

T&& x = ...;

我们使用x作为参数调用了一些函数:

f(x)

我们需要告诉f它是否会损坏x(或“取得x的所有权”,或“是最后一个使用x的客户”)。

设计此方法的一种方法是限定每次通话:

f(yours_now(x)) // ok to damage
f(still_mine(x)) // dont damage

并使不合格的电话非法。

另一种方法是将一种方式设为默认值:

或者:

f(yours_now(x)) // ok to damage
f(x) // dont damage

f(x) // ok to damage
f(still_mine(x)) // dont damage

因此,如果我们同意资格认证,每次使用都太笨重,我们应该默认为一种方式,哪种方式最好?好吧,让我们看看两种情况下意外选择默认值的成本:

在第一种情况下它可以损坏,但我们不小心说它不是。在这种情况下,我们失去了性能,因为制作了不必要的副本,但除此之外没什么大不了的。

在第二种情况下,不能破坏物体,但我们不小心说它是。这可能会导致难以检测到程序中的逻辑错误,因为当f返回时x现在处于损坏状态,但作者预计它不会出现。

所以第一种情况是选择的,因为它“更安全”。