3 回答
TA贡献1829条经验 获得超6个赞
正如另一个回答者已经指出的,为什么++i是左值是将其传递给引用。
int v = 0;
int const & rcv = ++v; // would work if ++v is an rvalue too
int & 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)
TA贡献1860条经验 获得超8个赞
其他人已经解决了后增量和前增量之间的功能差异。
就左值而言,i++由于它不引用变量,因此无法分配给它。它指的是计算值。
在分配方面,以下两种方式都没有意义:
i++ = 5;
i + 0 = 5;
因为pre-increment返回对增量变量的引用而不是临时副本,所以它++i是一个左值。
当您要增加迭代器对象(例如,STL中的对象)之类的东西可能比int的权重大得多时,出于性能原因而首选pre-increation成为一个特别好的主意。
- 3 回答
- 0 关注
- 479 浏览
添加回答
举报