为什么这两个右值引用示例有不同的行为?

时间:2016-02-10 12:35:14

标签: c++ rvalue-reference

第一个例子

int a = 0;
auto && b = ++a;
++a;
cout << a << b << endl;

打印22

第二个例子

int a = 0;
auto && b = a++;
++a;
cout << a << b << endl;

打印20

问题: 为什么在第3行中的第一个示例++a也会增加b,为什么在第二个示例中没有这样的行为?

更新: New question出现了。

3 个答案:

答案 0 :(得分:10)

因为预增量(++a)首先增加a的值,所以存储结果,然后返回对a的引用。现在ab有效地指向同一个对象。

然而,

后增量(a++)首先将a的当前值存储在临时,增量a中,并返回此临时值 - 您的右值ref指向该临时值。 ab指向不同的对象,更具体地说,b是在递增之前暂时保留a的值。

这就是为什么鼓励使用++it而不是it++用于迭代器和定义递增/递减的其他复杂对象的原因:后者创建一个临时副本,因此可能会慢一些。

答案 1 :(得分:3)

区别在于++a是左值,但a++不是。这由C ++ 14 [expr.pre.incr] / 1:

指定
  

通过添加1 [...] The来修改前缀++的操作数   操作数应是可修改的左值。 [...]结果是更新的操作数;这是一个左值

和[expr.post.incr] / 1:

  

[...]结果是prvalue。

现在我们考虑auto && b = ++a;++a是一个左值。 auto&&是转发参考。转发引用实际上可以绑定到左值:auto本身可以推导为引用类型。此代码推导为int &b = ++a;

当引用绑定到相同类型的左值时,引用会直接绑定,因此b成为a的另一个名称。

在第二个示例中,auto && b = a++;a++是prvalue。这意味着它没有相关联的地址,并且它与变量a不再有任何关系。此行与++a; auto && b = (a + 0);具有相同的行为。

首先,由于a++是prvalue,auto&&推导为int&&。 (即auto推导为int)。当非类类型的引用绑定到prvalue时,临时对象将从该值进行复制初始化。此对象的生命周期已扩展为与引用匹配。

所以第二种情况中的b绑定到a的另一个对象,一个&#34;临时&#34; int(这不是那么临时,因为它持续的时间与b一样长。)

参考绑定规则位于[dcl.init.ref]。

答案 2 :(得分:1)

在第二种情况下(后增量)b实际引用为(a ++)创建的临时值,因此增量不会影响b。