C ++ 11:为什么允许分配rvalues?

时间:2012-02-29 05:15:50

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

根据我的理解,返回rvalues对函数的引用是危险的原因是由于以下代码:

T&& f(T&& x) { do_something_to_T(x); return static_cast<T&&>(x); }
T f(const T& x) { T x2 = x; do_something_to_T(x2); return x2; }
T&& y = f(T());

这会将y留作未定义的悬空参考。

但是,我不明白为什么上面的代码甚至编译?是否有合理的理由将rvalue引用分配给另一个右值引用?粗略地说,rvalues不是“临时”,即在表达结束时会变得无效吗?能够分配它们对我来说似乎很愚蠢。

1 个答案:

答案 0 :(得分:8)

  

粗略地说,rvalues不是“临时”,即在表达结束时会变得无效吗?

不,他们不是。

鉴于您的功能f,这同样合法:

T t{};
T&& y = f(std::move(t));

这是完全有效的C ++ 11代码。它也很明确地发生了什么。

您的代码未定义的唯一原因是您传递了一个临时代码。但r值参考不一定是临时参考。

再详细说明一下,r值引用在概念上是对某些值的引用,某些操作被认为是可以做的,否则就不行了。

在C ++ 11中非常仔细地指定了R值引用。 l值引用可以绑定到任何非临时引用而无需强制转换或任何内容:

T t{};
T &y = t;

r值引用只能隐式绑定到临时或其他“xvalue”(在不久的将来肯定会消失的对象):

T &&x = T{};
T &&no = t; //Fail.

为了将r值引用绑定到非x值,您需要进行显式转换。 C ++ 11拼写此演员的方式是:std::move

T &&yes = std::move(t);

我所说的“某些操作”是“移动”。可以在两个条件下从一个对象移动:

  1. 无论如何它会消失。 IE:暂时的。
  2. 用户明确表示要离开它。
  3. 这些是r值引用可以绑定到某些内容的唯一两种情况。

    存在r值引用的原因主要有两个:支持移动语义并支持完美转发(需要一种新的引用类型,它们可以将时髦的转换机制挂钩,以及可能移动语义)。因此,如果您没有执行这两项操作中的一项,则使用&&的原因可疑。

    实际上,我甚至会在两种情况下说参数应该是&&:转发函数或移动构造函数/赋值。在所有其他情况下,如果您想允许移动,则按而不是&&进行输入。这样,您可以强制移动作为函数调用的一部分发生。对象可以从那里移动到最终目的地。