【问题标题】:Why Can const lvalue References Refer to Mutable rvalue References?为什么 const 左值引用可以引用可变右值引用?
【发布时间】:2014-01-07 21:22:57
【问题描述】:

在 C++11 中,可以使用可变右值引用来初始化 const 左值引用。然后,右值引用的值可以更改为 const 左值所指的内容产生可见的突变。这是一个例子:

int && rval = 3;
const int & lval = rval;

cout << "lval = " << lval << endl;
cout << "rval = " << rval << endl;

rval ++;

cout << "lval = " << lval << endl;

输出(来自 clang 3.2 和 gcc 4.8.2 都带有 -std=c++11):

lval = 3
rval = 3
lval = 4

我会原因是不能通过左值引用修改所指对象,但可以通过右值引用修改它。但是,我不明白为什么允许 const 左值引用可变对象。

有人可以解释这样做的理由并给出处理这种情况的最佳做法吗?另外,还有其他类似的可以颠覆constness的例子吗?

【问题讨论】:

  • 真希望这是UB的结果。

标签: c++ gcc c++11 initialization clang


【解决方案1】:

但是,我不明白为什么允许 const 左值引用可变对象

拥有const 对某事物的引用仅意味着您无法通过该引用修改该对象。这并不意味着任何人都不能更改对象。

假设你有一个函数:

void f(Foo const& bar);

函数向调用者声明它不会修改bar。而已。仅此而已,仅此而已。它没有说明bar 在执行f 时会发生什么(例如在另一个线程中);该语言无法表达这样的约束。

最后一点:

int && rval = 3;

rval 是一个左值。正如您的代码清楚地展示的那样,它有一个名称并且可以位于作业的左侧。右值引用和左值引用之间的区别在于右值引用可以绑定到右值——而不是它们本身就是右值。

这就是为什么给出类似的东西

void foo(unique_ptr<X>&& x)
{
    aVector.emplace_back(x);
}

不编译。 x 被声明为右值引用,但在 foo 内部它有一个名称,可以在赋值的左侧,并且是一个左值。将其移动到其他地方需要使用 move 或类似的:

void foo(unique_ptr<X>&& x)
{
    aVector.emplace_back(move(x)); // Ok
}

【讨论】:

  • 在这种情况下,它是第 3.10/10 节的 8 种类型中的哪一种?
  • 好的,我现在明白右值引用是可以绑定到右值的左值——谢谢。我仍然对 constness 有点不清楚。我认为我的困惑源于这种情况下的可变性与这种非法性之间的脱节:const int x=3; int &amp; lval = x; 我的猜测:如果一个对象最初被定义为 const,那么只有 const 名称可以引用它(并且该对象不会在任何情况下都是可变的)。接近了吗?
  • @Jefffrey:我不是价值类别方面的专家——我不是标准律师。 :)
  • @user:在这种情况下,您将删除 const,这是不合法的。在这种情况下,您将添加const,这很好。这与int x = 3; int const&amp; lval = x; 没有什么不同。
  • @Billy 我明白了。那么x++; 是合法的,lval++; 是不合法的。我可以肯定的是,是否有任何例外情况 removing const 是合法的?
猜你喜欢
  • 2020-01-23
  • 2017-04-15
  • 1970-01-01
  • 1970-01-01
  • 2013-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-09
相关资源
最近更新 更多