为什么说++i的效率比i++高?
不知道你是否听说过++i比i++快的说法,真的如此吗?
++i与i++的区别
这两个表达式从我们初学编程语言的时候就会接触到 。前者是自增后取值,后者是取值后自增 。
我们看一个简单的例子 。
#include <IOStream>using namespace std;int main(){ int a = 0; int b = 0; int c = a++;//int tmp = a;c=a;a = a + 1 int d = ++b;//b = b + 1;d = b; cout<<"c="<<c<<";d="<<d<<endl; return 0;}运行结果:
c=0;d=1
对于这个结果我们并不感到意外 。
另外我们还注意到另外一个有意思的现象:
//来源:公众号【编程珠玑】地址:https://www.yanbinghu.com#include <iostream>using namespace std;int main(){ int a = 0; int b = 0; int *c = &(a++); int *d = &(++b); return 0;}编译后报错:
main.cpp:7:19: error: lvalue required as unary ‘&’ operand int *c = &(a++);说&作用于左值,也就是说a++的结果并非左值 。但++b的结果是左值 。
可简单理解左值和右值:
- 左值,有名对象,可赋值
- 右值,临时对象,不可被赋值
运算符重载
在《运算符重载》一文中已经说到了运算符的重载,通过前面的例子也发现了,对于内置类型,前置自增返回对象的引用,而后置自增返回对象的原值(但非左值) 。
基于上述原则,一个前置版本和后置版本的常见实现如下:
//来源:公众号【编程珠玑】地址:https://www.yanbinghu.comclass Test{public: Test& operator++();//前置自增 const Test operator++(int);//后置自增private: int curPos; //当前位置};/*前置自增实现范式*/Test& Test::operator++(){ ++curPos; //自增 return *this; //取值}/*后置自增实现范式,为了与前置区分开,多了一个int参数,但从来没用过*/const Test Test::operator++(int){ Test tmp = *this; //取值 ++curPos; //自增 return tmp;}仔细观察后,我们发现前置自增,先自增,后返回原对象的对象;没有产生任何临时对象;而后置自增,先保存原对象,然后自增,最后返回该原临时对象,那么它就需要创建和销毁,这样一来,效率孰高孰低就很清楚了 。
在不进行赋值的情况下,内置类型前置和后置自增的汇编都是一样的呢!
void test(){ int i = 0; i++; //++i;}汇编:
push rbpmov rbp, rspmov Dword PTR [rbp-4], 0add DWORD PTR [rbp-4], 1noppop rbpret不过,赋值的情况下,并且不开启编译器优化,它们的汇编代码还是有差别的,有兴趣的可以试试 。
总结
对于内置类型,前置和后置自增或者自减在编译器优化的情况下,两者并无多大差别,而对于自定义类型,如无特别需要,人们似乎更加偏爱前置自增或自减,因为后置自增常常会产生临时对象 。
但是,又能提高多少效率呢?
【为什么说++i的效率比i++高?】
推荐阅读
- 临时、永久挂载 Ubuntu移动硬盘的挂载
- 毫色如银说白茶
- 大家都在说的分布式系统到底是什么?
- 梦见领导和自己说话还很亲密 梦见领导和自己说话
- 羽绒服有鸭毛味是不是说明质量差 羽绒服一股鸭毛的味道是好还是坏
- 男生和自己接吻又不明确关系 男生没确定关系为什么要吻你
- 贵州茅台|茅台酒厂都说是假酒,为何要被证明对人体有害才能赔付
- 资产配置|职场上不会说话的人,后来都吃亏了
- 男生牵手但是没有说喜欢 男生牵我手但没表白是什么意思
- 话说防暑降温茶