(转)前置++和后置++的区别
今天在阅读《google c++ 编程风格》的文档的时候,5.10. 前置自增和自减:有一句话引起了我的注意:
对于迭代器和其他模板对象使用前缀形式 (++i) 的自增, 自减运算符.,理由是 前置自增 (++i) 通常要比后置自增 (i++) 效率更高。于是我查了查前置++和后置++的区别。
注意:《more effective c++》条款8也专门叙述了问题。后来我发现,下面的文章基本就是它的翻版,哈哈
前置++和后置++的区别
《C专家编程》中有如下描述(P276,人民邮电出版社):
++a表示取a的地址,增加它的内容,然后把值放在寄存器中;
a++表示取a的地址,把它的值装入寄存器,然后增加内存中的a的值;(也就是说操作的时候用到的都是寄存器里面的值,即自增前的值)
另外,网上找了篇文章,通过从运算符重载的角度来探讨他们的不同,如下:
假设有一个类Age,描述年龄。该类重载了前置++和后置++两个操作符,以实现对年龄的自增。
class Age { public: Age& operator++() //前置++ { ++i; return *this; } const Age operator++(int) //后置++ { Age tmp = *this; ++(*this); //利用前置++ return tmp; } Age& operator=(int i) //赋值操作 { this->i = i; return *this; } private: int i; };
从上述代码,我们可以看出前置++和后置++,有3点不同:
- 返回类型不同
- 形参不同
- 代码不同
- 效率不同
返回值类型的区别
前置++的返回类型是Age&,后置++的返回类型const Age。这意味着,前置++返回的是左值,后置++返回的是右值。(关于左值和右值的讨论很多,见本文下面)
左值和右值,决定了前置++和后置++的用法。
int main() { Age a; (a++)++; //编译错误 ++(a++); //编译错误 a++ = 1; //编译错误 (++a)++; //OK ++(++a); //OK ++a = 1; //OK }
++的类型是const Age,自然不能对它进行前置++、后置++、赋值等操作。
++a的类型是Age&,当然可以对它进行前置++、后置++、赋值等操作
注:我们只要重载++时,只要认清前置++是没有参数的,后置++是有一个int型参数的就行了,实际调用的区分是编译器的事!
a++的返回类型为什么要是const对象呢?
有两个原因:
- 如果不是const对象,a(++)++这样的表达式就可以通过编译。但是,其效果却违反了我们的直觉 。a其实只增加了1,因为第二次自增作用在一个临时对象上。
- 另外,对于内置类型,(i++)++这样的表达式是不能通过编译的。自定义类型的操作符重载,应该与内置类型保持行为一致 。
a++的返回类型如果改成非const对象,肯定能通过编译,但是我们最好不要这样做。
++a的返回类型为什么是引用呢?
这样做的原因应该就是:与内置类型的行为保持一致。前置++返回的总是被自增的对象本身。因此,++(++a)的效果就是a被自增两次。
形参的区别
前置++没有形参,而后置++有一个int形参,但是该形参也没有被用到。很奇怪,难道有什么特殊的用意?
其实也没有特殊的用意,只是为了绕过语法的限制。
前置++与后置++的操作符重载函数,函数原型必须不同。否则就违反了“重载函数必须拥有不同的函数原型”的语法规定。
虽然前置++与后置++的返回类型不同,但是返回类型不属于函数原型。为了绕过语法限制,只好给后置++增加了一个int形参。
原因就是这么简单,真的没其他特殊用意。其实,给前置++增加形参也可以;增加一个double形参而不是int形参,也可以。只是,当时就这么决定了。
代码实现的区别
前置++的实现比较简单,自增之后,将*this返回即可。需要注意的是,一定要返回*this。
后置++的实现稍微麻烦一些。因为要返回自增之前的对象,所以先将对象拷贝一份,再进行自增,最后返回那个拷贝。
在Age的代码中,后置++利用了前置++来实现自增。这样做是为了避免“自增的代码”重复。
在本例中,自增的代码很简单,就是一行++i,没有必要这样做。但是在其它自增逻辑复杂的例子中,这么做还是很有必要的。
效率的区别
如果不需要返回自增之前的值,那么前置++和后置++的计算效果都一样。但是,我们仍然应该优先使用前置++,尤其是对于用户自定义类型的自增操作。
前置++的效率更高,理由是:后置++会生成临时对象。
从Age的后置++的代码实现也可以看出这一点。
const Age operator++(int) //后置++ { Age tmp = *this; ++(*this); //利用前置++ return tmp; }
很明显,tmp是一个临时对象,会造成一次构造函数和一次析构函数的额外开销。虽然,编译器在某些情况下可以优化掉这些开销。但是,我们最好不要依赖编译器的行为。
所以,在非内置类型的时候,尽量使用前置++,因为效率高(后置自增,效率低)
原文链接:http://blog.csdn.net/randyjiawenjie/article/details/6747720
转载于:https://www.cnblogs.com/balingybj/p/4736195.html
(转)前置++和后置++的区别相关推荐
- 前置++和后置++的区别
今天在阅读<google c++ 编程风格>的文档的时候,5.10. 前置自增和自减:有一句话引起了我的注意: 对于迭代器和其他模板对象使用前缀形式 (++i) 的自增, 自减运算符.,理 ...
- JavaScript运算符:递增递减运算符前置和后置的区别
从两段代码说起 var num1 = 2; var num2 = 20; var num3 = --num1 + num2; var num4 = num1 + num2; console.log(n ...
- C 语言里++前置和后置的区别
在c语言中,++和+1基本相同,都是在原有变量上加上1,一下三条命令结果是相同的 b++ b=b+1 b+=1 在一行代码中,如果++前置,编译器首先执行++,再执行其他代码.如果++后置,编译器先执 ...
- C++之运算符重载(前置++和后置++)
今天在阅读<google c++ 编程风格>的文档的时候,5.10. 前置自增和自减:有一句话引起了我的注意: 对于迭代器和其他模板对象使用前缀形式 (++i) 的自增, 自减运算符.,理 ...
- c++中的前置和后置加加没你想的这么简单
1.前置++和后置++的区别1: 前置是先加后赋值,后置是先赋值再加. 2.前置++比后置++运行的速度快: 在汇编底层中后置++会比前置++多一行. 当然我这demo不是很准确毕竟也是有偶然的,但是 ...
- C++回顾之前置++、后置++、不等号!及赋值运算符重载
运算符重载的主要目的是为了让类对象能像普通数据类型一样能够进行加减乘除,自加自减等操作,非常直观方便.现在来回顾C++的自加减(分前置与后置)以及不等号非运算符,赋值运算符的重载. 1 ++重载 (1 ...
- [凯圣王]碳水在身体内的去向/碳水前置后置的区别/碳水循环计划的简聊/训练前什么时间吃碳水
碳水在身体内的去向/碳水前置后置的区别/碳水循环计划的简聊/训练前什么时间吃碳水 一.视频 二.碳水的种类 三.碳.蛋.脂 转换关系 四.碳水在身体中的储存数量 五.碳水什么时候补充 六.碳水循环饮食 ...
- 前置++与后置++、前置--与后置--
前置++与后置++.前置–与后置– ++与–的知识点相同,在此只记录前置++与后置++的知识点. 1 基本区别 前置++是先自加再使用,而后置++是先使用再自加! 此处自加自减指的是变量的值,使用指的 ...
- 攀登Spring珠穆朗玛峰:前置与后置处理器
文章目录 Spring的前置与后置处理器 前提知识 前置与后置处理器定义 前置处理器:BeanFactoryPostProcessor `postProcessBeanFactory`调用 后置处理器 ...
最新文章
- Python组合数据类型之序列类型
- [2774]小P的故事——神奇的发票报销 (sdut)
- 改进,从一个数组中找出 N 个数,其和为 M 的所有可能
- Centos RSYNC服务搭建
- SAP云平台cf push命令报错误码44的解决方法
- 使用代码执行organization unit determination逻辑
- 如何利用业务时间提升自我
- Problem Collection II 构造
- 如何将应用程序分为三个主要层
- idea中Tomcat启动乱码问题
- 早该知道的7个JavaScript技巧
- 《善用佳软:高效能人士的软件应用之道》一2.5 PDF:跨平台文档解决方案
- 科密考勤机RS485接头接线方法和加班计算公式
- 通过 Kali Linux 暴力破解 WiFi
- php怎么把图片设置为背景,ppt怎么把图片设为背景
- python学习:用两种思路计算质数与合数
- CentOS7的locale配置
- 线上抓娃娃机火了三个月了,你玩了吗?
- 修改 vscode 中主题注释中文的斜体格式
- 计算机动画基础 吴,chap3计算机动画的图形基础-1(2学时)-2010.9.16.ppt