第一个例子
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出现了。
答案 0 :(得分:10)
因为预增量(++a
)首先增加a
的值,所以存储结果,然后返回对a
的引用。现在a
和b
有效地指向同一个对象。
后增量(a++
)首先将a
的当前值存储在临时,增量a
中,并返回此临时值 - 您的右值ref指向该临时值。 a
和b
指向不同的对象,更具体地说,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。