【问题标题】:C++11: Why is assigning rvalues allowed?C++11:为什么允许分配右值?
【发布时间】:2012-02-29 05:15:50
【问题描述】:

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

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

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

【问题讨论】:

  • Eric Lippert 谈到了实现一个允许在 this post 中返回 ref 的 C# 变体,并且还涵盖了由此产生的许多用例。
  • 哪个编译器编译它? o.O... 因为它不能编译 - 你不能用 T 初始化 T&amp;&amp;
  • @AzzA:呃,你可以用右值初始化一个右值引用,这就是它们的全部意义。
  • 另外,这是通常的引用绑定。你必须能够绑定引用,所以这个问题看起来很傻。
  • @CatPlusPlus 但是这个特定的代码不能编译:没有转发...你需要return std::forward&lt;T&gt;(x);

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


【解决方案1】:

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

不,他们不是。

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

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

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

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

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

R 值引用在 C++11 中非常仔细地指定。左值引用可以绑定到任何非临时对象,而不需要强制转换或任何东西:

T t{};
T &y = t;

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

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

为了将 r 值引用绑定到非 xvalue,您需要进行显式转换。 C++11 拼写这个演员表的方式很清楚:std::move:

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

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

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

这是仅有的两种 r 值引用可以绑定到某物的情况。

存在 r-value 引用的原因有两个:支持移动语义和支持完美转发(这需要一种新的引用类型,他们可以将时髦的铸造机制挂钩,以及潜在的移动语义)。因此,如果您不执行这两个操作之一,那么使用&amp;&amp; 的原因是可疑的。

【讨论】:

  • 如果 f 是一个合法的函数,它不应该在临时变量上工作,它的定义不应该是:T&amp; f(T&amp;) 所以它在收到临时变量而不是导致未定义时抛出编译错误行为?如果它不是临时的,为什么不使用普通参考?您可以从普通参考中移动。
  • @Clinton:是的,您可以从左值参考移动。但是你不能通过一个临时的。您假设您的选择是“临时的函数”和“不能临时的函数”。为什么不允许函数获取任何内容并使其与所给定的内容一起工作?双方都更容易。
  • @Nicol 在最后一段中,您是否说 - 除了移动构造函数/赋值的情况 - 每当我要使用 T const&amp;- 和 T&amp;&amp; 重载函数时-parameter 版本,我应该只提供一个 T-parameter 版本,我从参数中移动?
  • @Reizo:自从发表这篇文章以来的 8 年里,我重新考虑了我对右值引用参数类型的立场。所以我删除了最后一段。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-05
  • 2019-03-11
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
  • 2010-11-13
  • 1970-01-01
相关资源
最近更新 更多