为什么将引用绑定到右值是合法的?

问题描述 投票:0回答:1

据我了解,从函数返回右值引用是危险的原因是由于以下代码:

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
成为未定义的悬空引用。

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

c++ c++11 language-lawyer rvalue-reference temporary-objects
1个回答
10
投票

粗略地说,右值不是应该是“临时的”,即在表达式末尾无效吗?

不,他们不是。

鉴于您的功能

f
,这同样合法:

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

这是完全有效的 C++11 代码。而且它也明确定义了会发生什么。

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

更详细地说,从概念上讲,右值引用是对某个值的引用,在该值中某些操作被认为可以执行,否则这些操作是不可以执行的。

C++11 中非常仔细地指定了 R 值引用。左值引用可以绑定到任何非临时引用,而不需要强制转换或任何其他操作:

T t{};
T &y = t;

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

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

为了将右值引用绑定到非x值,您需要进行显式强制转换。 C++11 拼写此转换的方式很能说明问题:

std::move
:

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

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

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

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

右值引用存在的原因有两个:支持移动语义和支持完美转发(这需要一种新的引用类型,可以将时髦的转换机制挂钩,以及潜在的移动语义)。因此,如果您不执行这两个操作之一,那么使用

&&
的理由是值得怀疑的。

© www.soinside.com 2019 - 2024. All rights reserved.