肥皂起泡泡
正如另一个回答者已经指出的,为什么++i是左值是将其传递给引用。int v = 0;int const & rcv = ++v; // would work if ++v is an rvalue tooint & rv = ++v; // would not work if ++v is an rvalue第二条规则的原因是,当引用是对const的引用时,允许使用文字初始化引用:void taking_refc(int const& v);taking_refc(10); // valid, 10 is an rvalue though!您为什么要问我们为什么要引入右值。好了,在为以下两种情况建立语言规则时会出现这些术语:我们想要一个定位器值。那将代表一个包含可以读取的值的位置。我们要表示一个表达式的值。以上两点摘自C99标准,其中包括这个非常好的脚注,非常有帮助:[名称“左值”最初来自赋值表达式E1 = E2,其中左操作数E1必须是(可修改的)左值。最好将其表示为对象“定位器值”。在本国际标准中有时称为“ rvalue”的内容称为“表达式的值”。]定位器的值称为lvalue,而评估该位置所得到的值称为rvalue。根据C ++标准,这也是正确的(谈论从左值到右值的转换):4.1 / 2:由左值表示的对象中包含的值是右值结果。结论使用上述语义,现在很清楚为什么i++不是左值而是右值。因为返回的表达式不再位于i(它已递增!),所以它只是可能值得关注的值。修改返回的值是i++没有意义的,因为我们没有可以再次读取该值的位置。因此,标准说它是一个右值,因此它只能绑定到对常量的引用。但是,相反,所返回的表达式++i是的位置(左值)i。像in那样引发从左值到右值的转换int a = ++i;将读取其中的值。或者,我们可以对其进行参考,然后稍后读出该值:int &a = ++i;。还请注意生成右值的其他情况。例如,所有临时变量都是右值,二进制/一元+和负号的结果以及所有不是引用的返回值表达式。所有这些表达式都不位于命名对象中,而是仅带有值。这些值当然可以由不恒定的对象备份。下一个C ++版本将包括所谓的rvalue references那个,即使它们指向nonconst,也可以绑定到右值。基本原理是能够“窃取”那些匿名对象的资源,并避免使用副本进行复制。假设一个类类型的前缀++(返回Object&)和后缀++(返回Object)都已重载,则以下内容将首先导致复制,而在第二种情况下,它将从右值中窃取资源:Object o1(++a); // lvalue => can't steal. It will deep copy.Object o2(a++); // rvalue => steal resources (like just swapping pointers)