关于++i和i++的效率问题

zyqde_0802 2011-04-21 04:16:12
C++ Primer 4的162页,提到了这样一句“前自增操作需要做的工作更少,只需要加以后返回加一后的结果即可”,有点不清楚了,
如j = ++i;不是分两步吗?一:i = i+1;二:j=i;吗?j = i++;不就是把前面的两部倒过来就行吗?

怎么理解?
还有在
for(int i=0; i<n; i++)与for(int i=0; i<n; ++i)效率有区别吗?

若有,当n很大时,可能会有明显的效率差别。
...全文
322 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
spaceismine 2011-10-22
  • 打赏
  • 举报
回复
别骗人:
主要还是给大家看看效率,因为看很多人代码我很无语:
C++primer4写了这样一段话,我今天做了实验证明他说的是正确的:

建议:只有在必要时才使用后置操作符

有使用 C 语言背景的读者可能会觉得奇怪,为什么要在程序中使用前自增操作。道理很简单:因为前置操作需要做的工作更少,只需加 1 后返回加 1 后的结果即可。而后置操作符则必须先保存操作数原来的值,以便返回未加 1 之前的值作为操作的结果。对于 int 型对象和指针,编译器可优化掉这项额外工作。但是对于更多的复杂迭代器类型,这种额外工作可能会花费更大的代价。因此,养成使用前置操作这个好习惯,就不必操心性能差异的问题。

#include<cstdio>
#include<cstring>
#include<vector>
#include<cstdint>

int main()
{
std::vector<std::uint32_t> v(5);
uint32_t i(0);
++i;
i++;
std::vector<std::uint32_t>::iterator iter(v.begin());
++iter;
iter++;
return 0;
}
第一个是测++i和i++的效率
uint32_t i(0);
0041182E mov dword ptr [ebp-30h],0
++i;
00411835 mov eax,dword ptr [ebp-30h]
00411838 add eax,1
0041183B mov dword ptr [ebp-30h],eax
i++;
0041183E mov eax,dword ptr [ebp-30h]
00411841 add eax,1
00411844 mov dword ptr [ebp-30h],eax
汇编代码是一样的因为他们是整形。
但是下面就不一样了:
++iter;
00411857 lea ecx,[ebp-44h]
0041185A call std::_Vector_iterator<std::_Vector_val<unsigned int,std::allocator<unsigned int> > >::operator++ (4110F0h)
iter++;
0041185F push 0
00411861 lea eax,[ebp-124h]
00411867 push eax
00411868 lea ecx,[ebp-44h]
0041186B call std::_Vector_iterator<std::_Vector_val<unsigned int,std::allocator<unsigned int> > >::operator++ (41133Eh)
00411870 lea ecx,[ebp-124h]
00411876 call std::_Vector_iterator<std::_Vector_val<unsigned int,std::allocator<unsigned int> > >::~_Vector_iterator<std::_Vector_val<unsigned int,std::allocator<unsigned int> > > (4110B4h)
可以看到iter++调用了++iter,并且做了7句汇编,而++iter只做了2句,证明++iter效率是iter++的3.5倍。

其实还有!=号的效率是比<号的效率高的,大家可以试试
赵4老师 2011-04-22
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 pink9527 的回复:]
有一本讲效率的书上说++i比i++效率高很多
[/Quote]
不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。
fight_flight 2011-04-21
  • 打赏
  • 举报
回复
在两者的作用一样时推荐使用++i,一旦i为一个自定义类型的参数,且大量运行这类语句,++i要比i++效率高出不少。因为i++要保存一个临时变量并返回。
zicheng_lin 2011-04-21
  • 打赏
  • 举报
回复
如果是int等内置类型的变量,2者的相差无几,但是如果是其他类型就有区别了,比如一个复杂的迭代器类型,复制一次,代价不小的。
xspace_time 2011-04-21
  • 打赏
  • 举报
回复
有一本讲效率的书上说++i比i++效率高很多
zyqde_0802 2011-04-21
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 xyy410874116 的回复:]

举个例子:
int a=0;
int b=a++;
int c=++a;

运行的结果是:a=0;b=0;c=1;
OK……
[/Quote]

??????????????...............
「已注销」 2011-04-21
  • 打赏
  • 举报
回复
primer的意思应该是针对于自定义类的运算符重载的效率。
考虑类Foo定义如下

class Foo {
public:
int data;
public:
Foo() : data(0) { }
Foo(int data) : data(data) { }
Foo(const Foo &foo) : data(foo.data) { }
public:
Foo &operator ++() { ++(this->data); return (*this); }
Foo operator ++(int) { Foo retval(*this); ++(this->data); return (retval); }
};


可见Post-increment在实现上多产生了一个实例,当对象构造开销很大时,这会带来效率上差异。
因此,如STL迭代器等推荐使用Pre-increment。
l523669057 2011-04-21
  • 打赏
  • 举报
回复
当i是内置数据类型时,编译器进行优化后是一样的,但当i是用户定义的类类型时就会出现效率差异,但倒低谁快得看类设计者怎么重载++算运符,不过通常情况下i++是通过++i实现的 谁快也就一目了然了
xyy410874116 2011-04-21
  • 打赏
  • 举报
回复
举个例子:
int a=0;
int b=a++;
int c=++a;

运行的结果是:a=0;b=0;c=1;
OK……
zyqde_0802 2011-04-21
  • 打赏
  • 举报
回复
汇编看了,没有差别的,就是不明白书里的意思。
eye_119_eye 2011-04-21
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 luciferisnotsatan 的回复:]
i++生成一个临时变量,所以比如用在for(int i=0; i<n; i++)里,效率不如 ++i。但这个是纯理论上的,实际上没什么差异,消耗的时间不再这块。而且优化后,可能和 ++i是一样的代码
[/Quote]
++
gangyilovevc 2011-04-21
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 zhao4zhong1 的回复:]

VC调试时按Alt+8,TC或BC用TD调试,打开汇编窗口看每句C对应的汇编并单步执行一遍不就啥都明白了吗。
(Linux或Unix下应该也可以在用GDB调试时,看每句C对应的汇编并单步执行。)
[/Quote]
++
luciferisnotsatan 2011-04-21
  • 打赏
  • 举报
回复
i++生成一个临时变量,所以比如用在for(int i=0; i<n; i++)里,效率不如 ++i。但这个是纯理论上的,实际上没什么差异,消耗的时间不再这块。而且优化后,可能和 ++i是一样的代码
xmu_才盛 2011-04-21
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 a199228 的回复:]
i++返回的是一个临时变量,而++i返回的是i本身。并且在很多实现方式中,后置的++是有前置的++来实现的。因而
效率上讲是有差别的。

尤其是对大型的变量而言。如i是一个很大的结构体,或者很大的一个类。这就会造成过大的浪费

++i的结果应该是一个左值,而i++的结果应该是个右值

很多书里面主张用++i。
[/Quote]

不错
赵4老师 2011-04-21
  • 打赏
  • 举报
回复
VC调试时按Alt+8,TC或BC用TD调试,打开汇编窗口看每句C对应的汇编并单步执行一遍不就啥都明白了吗。
(Linux或Unix下应该也可以在用GDB调试时,看每句C对应的汇编并单步执行。)
tuning工作者 2011-04-21
  • 打赏
  • 举报
回复
i++ 先返回自身的值然后再自增
++i 先自增再返回自增后的值
s_hhm 2011-04-21
  • 打赏
  • 举报
回复
没有本质区别(个人以为)主要区别在于 i++;先使用后自加.
++i 先自加,后使用
例子:
int i=1;
j=i++;
运行后 j=1;i=2
int i=1;
j=++i;
运行后 j=2;i=2;
回答完毕!~
pathuang68 2011-04-21
  • 打赏
  • 举报
回复
一般大家都说++i快过i++。
原因也有不同的说法。

记住有这么回事就好了。

俺最初喜欢用++i,后来改成了i++,现在又变成了++i...
direction917 2011-04-21
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 a199228 的回复:]

i++返回的是一个临时变量,而++i返回的是i本身。并且在很多实现方式中,后置的++是有前置的++来实现的。因而
效率上讲是有差别的。

尤其是对大型的变量而言。如i是一个很大的结构体,或者很大的一个类。这就会造成过大的浪费

++i的结果应该是一个左值,而i++的结果应该是个右值

很多书里面主张用++i。
[/Quote]
学习了。
a199228 2011-04-21
  • 打赏
  • 举报
回复
i++返回的是一个临时变量,而++i返回的是i本身。并且在很多实现方式中,后置的++是有前置的++来实现的。因而
效率上讲是有差别的。

尤其是对大型的变量而言。如i是一个很大的结构体,或者很大的一个类。这就会造成过大的浪费

++i的结果应该是一个左值,而i++的结果应该是个右值

很多书里面主张用++i。
加载更多回复(1)
一、prometheus简介 Prometheus是一个开源的系统监控和告警系统,现在已经加入到CNCF基金会,成为继k8s之后第二个在CNCF维护管理的项目,在kubernetes容器管理系统中,通常会搭配prometheus进行监控,prometheus支持多种exporter采集数据,还支持通过pushgateway进行数据上报,Prometheus再性能上可支撑上万台规模的集群。 二、prometheus架构图 三、prometheus组件介绍 1.Prometheus Server: 用于收集和存储时间序列数据。 2.Client Library: 客户端库,检测应用程序代码,当Prometheus抓取实例的HTTP端点时,客户端库会将所有跟踪的metrics指标的当前状态发送到prometheus server端。 3.Exporters: prometheus支持多种exporter,通过exporter可以采集metrics数据,然后发送到prometheus server端 4.Alertmanager: 从 Prometheus server 端接收到 alerts 后,会进行去重,分组,并路由到相应的接收方,发出报警,常见的接收方式有:电子邮件,微信,钉钉, slack等。 5.Grafana:监控仪表盘 6.pushgateway: 各个目标主机可上报数据到pushgatewy,然后prometheus server统一从pushgateway拉取数据。 四、课程亮点 五、效果图展示 六、讲师简介 先超(lucky):高级运维工程师、资深DevOps工程师,在互联网上市公司拥有多年一线运维经验,主导过亿级pv项目的架构设计和运维工作 主要研究方向: 1.云计算方向:容器 (kubernetes、docker),虚拟化(kvm、Vmware vSphere),微服务(istio),PaaS(openshift),IaaS(openstack)等2.系统/运维方向:linux系统下的常用组件(nginx,tomcat,elasticsearch,zookeeper,kafka等),DevOps(Jenkins+gitlab+sonarqube+nexus+k8s),CI/CD,监控(zabbix、prometheus、falcon)等 七、课程大纲

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧