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

Cli*_*ton 5 c++ rvalue rvalue-reference c++11

根据我的理解,返回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());
Run Code Online (Sandbox Code Playgroud)

这留下y了一个未定义的悬空参考.

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

Nic*_*las 10

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

不,他们不是.

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

T t{};
T&& y = f(std::move(t));
Run Code Online (Sandbox Code Playgroud)

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

您的代码未定义的唯一原因是您传递了一个临时代码.但是r值引用不一定是临时值.

为了进一步详细说明,r值引用在概念上是对某些操作被认为可以执行的值的引用,否则这样做是不可行的.

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

T t{};
T &y = t;
Run Code Online (Sandbox Code Playgroud)

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

T &&x = T{};
T &&no = t; //Fail.
Run Code Online (Sandbox Code Playgroud)

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

T &&yes = std::move(t);
Run Code Online (Sandbox Code Playgroud)

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

  1. 无论如何它会消失.IE:暂时的.
  2. 用户明确表示要离开它.

这些是r值引用可以绑定到某些东西的唯一两种情况.

存在r值引用的原因有两个:支持移动语义并支持完美转发(需要一种新的引用类型,它们可以将时髦的转换机制连接到一起,以及可能移动语义).因此,如果你没有做这两个操作中的一个,使用a的原因&&是可疑的.

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