++i和i++,为什么++i运行速度更快一些?
这个问题在面试中也会经常问到,对于这个问题的回答我们可以分两种情况:
①:当i的类型为常见的数据类型(int float ....)的时候,i++和++i是没有区别的,效率一样,从汇编指令也可以看出,相差无几
int main(void)
{
int i=0;
int x=0;
i++;
++i;
x=i++;
x=++i;
cout<<i;
return 0;
}
对应的汇编代码如下:
208 [1] int i=0;
0x40166d <+ 13> c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
209 [1] int x=0;
0x401674 <+ 20> c7 45 f8 00 00 00 00 movl $0x0,-0x8(%rbp)
210 [1] i++;
0x40167b <+ 27> 83 45 fc 01 addl $0x1,-0x4(%rbp)
211 [1] ++i;
0x40167f <+ 31> 83 45 fc 01 addl $0x1,-0x4(%rbp)
212 [1] x=i++;
0x401683 <+ 35> 8b 45 fc mov -0x4(%rbp),%eax
0x401686 <+ 38> 8d 50 01 lea 0x1(%rax),%edx
0x401689 <+ 41> 89 55 fc mov %edx,-0x4(%rbp)
0x40168c <+ 44> 89 45 f8 mov %eax,-0x8(%rbp)
213 [1] x=++i;
0x40168f <+ 47> 83 45 fc 01 addl $0x1,-0x4(%rbp)
0x401693 <+ 51> 8b 45 fc mov -0x4(%rbp),%eax
0x401696 <+ 54> 89 45 f8 mov %eax,-0x8(%rbp)
②:当类型为自建的类型比如:类 ,这个时候,区别就出来了,++i的效率高于i++原因如下:
#include "bits/stdc++.h"
using namespace std;
class Time
{
private:
int hours; // 0 到 23
int minutes; // 0 到 59
public:
// 所需的构造函数
Time(){
hours = 0;
minutes = 0;
}
Time(int h, int m){
hours = h;
minutes = m;
}
// 显示时间的方法
void displayTime()
{
cout << "H: " << hours << " M:" << minutes <<endl;
}
// 重载前缀递增运算符( ++ )
Time operator++ ()
{
++minutes; // 对象加 1
if(minutes >= 60)
{
++hours;
minutes -= 60;
}
return Time(hours, minutes);
}
// 重载后缀递增运算符( ++ )
Time operator++( int )
{
// 保存原始值
Time T(hours, minutes); //这里是重点 !这里使用了复制构造函数,增加了开销 效率降低
// 对象加 1
++minutes;
if(minutes >= 60)
{
++hours;
minutes -= 60;
}
// 返回旧的原始值
return T;
}
};
int main()
{
Time T1(11, 59), T2(10,40);
++T1; // T1 加 1
T1.displayTime(); // 显示 T1
++T1; // T1 再加 1
T1.displayTime(); // 显示 T1
T2++; // T2 加 1
T2.displayTime(); // 显示 T2
T2++; // T2 再加 1
T2.displayTime(); // 显示 T2
return 0;
}
汇编代码对应 后缀++:
从这里开始:
236 [1] Time operator++( int )
0x402f80 55 push %rbp
0x402f81 <+ 1> 48 89 e5 mov %rsp,%rbp
0x402f84 <+ 4> 48 83 ec 30 sub $0x30,%rsp
0x402f88 <+ 8> 48 89 4d 10 mov %rcx,0x10(%rbp)
0x402f8c <+ 12> 89 55 18 mov %edx,0x18(%rbp)
239 [1] Time T(hours, minutes); //这里为了保存值,做了这么多操作,降低了效率的真正原因
0x402f8f <+ 15> 48 8b 45 10 mov 0x10(%rbp),%rax
0x402f93 <+ 19> 8b 48 04 mov 0x4(%rax),%ecx
0x402f96 <+ 22> 48 8b 45 10 mov 0x10(%rbp),%rax
0x402f9a <+ 26> 8b 10 mov (%rax),%edx
0x402f9c <+ 28> 48 8d 45 f8 lea -0x8(%rbp),%rax
0x402fa0 <+ 32> 41 89 c8 mov %ecx,%r8d
0x402fa3 <+ 35> 48 89 c1 mov %rax,%rcx
0x402fa6 <+ 38> e8 a5 ff ff ff callq 0x402f50 <Time::Time(int, int)>
241 [1] ++minutes;
0x402fab <+ 43> 48 8b 45 10 mov 0x10(%rbp),%rax
0x402faf <+ 47> 8b 40 04 mov 0x4(%rax),%eax
0x402fb2 <+ 50> 8d 50 01 lea 0x1(%rax),%edx
0x402fb5 <+ 53> 48 8b 45 10 mov 0x10(%rbp),%rax
0x402fb9 <+ 57> 89 50 04 mov %edx,0x4(%rax)
242 [1] if(minutes >= 60)
0x402fbc <+ 60> 48 8b 45 10 mov 0x10(%rbp),%rax
0x402fc0 <+ 64> 8b 40 04 mov 0x4(%rax),%eax
0x402fc3 <+ 67> 83 f8 3b cmp $0x3b,%eax
0x402fc6 <+ 70> 7e 20 jle 0x402fe8 <Time::operator++(int)+104>
244 [1] ++hours;
0x402fc8 <+ 72> 48 8b 45 10 mov 0x10(%rbp),%rax
0x402fcc <+ 76> 8b 00 mov (%rax),%eax
0x402fce <+ 78> 8d 50 01 lea 0x1(%rax),%edx
0x402fd1 <+ 81> 48 8b 45 10 mov 0x10(%rbp),%rax
0x402fd5 <+ 85> 89 10 mov %edx,(%rax)
245 [1] minutes -= 60;
0x402fd7 <+ 87> 48 8b 45 10 mov 0x10(%rbp),%rax
0x402fdb <+ 91> 8b 40 04 mov 0x4(%rax),%eax
0x402fde <+ 94> 8d 50 c4 lea -0x3c(%rax),%edx
0x402fe1 <+ 97> 48 8b 45 10 mov 0x10(%rbp),%rax
0x402fe5 <+ 101> 89 50 04 mov %edx,0x4(%rax)
248 [1] return T;
0x402fe8 <+ 104> 48 8b 45 f8 mov -0x8(%rbp),%rax
249 [1] }
汇编代码对应 前缀++:
225 [1] Time operator++ ()
0x403000 55 push %rbp
0x403001 <+ 1> 48 89 e5 mov %rsp,%rbp
0x403004 <+ 4> 48 83 ec 30 sub $0x30,%rsp
0x403008 <+ 8> 48 89 4d 10 mov %rcx,0x10(%rbp)
227 [1] ++minutes; //进来直接就加了
0x40300c <+ 12> 48 8b 45 10 mov 0x10(%rbp),%rax
0x403010 <+ 16> 8b 40 04 mov 0x4(%rax),%eax
0x403013 <+ 19> 8d 50 01 lea 0x1(%rax),%edx
0x403016 <+ 22> 48 8b 45 10 mov 0x10(%rbp),%rax
0x40301a <+ 26> 89 50 04 mov %edx,0x4(%rax)
228 [1] if(minutes >= 60)
0x40301d <+ 29> 48 8b 45 10 mov 0x10(%rbp),%rax
0x403021 <+ 33> 8b 40 04 mov 0x4(%rax),%eax
0x403024 <+ 36> 83 f8 3b cmp $0x3b,%eax
0x403027 <+ 39> 7e 20 jle 0x403049 <Time::operator++()+73>
230 [1] ++hours;
0x403029 <+ 41> 48 8b 45 10 mov 0x10(%rbp),%rax
0x40302d <+ 45> 8b 00 mov (%rax),%eax
0x40302f <+ 47> 8d 50 01 lea 0x1(%rax),%edx
0x403032 <+ 50> 48 8b 45 10 mov 0x10(%rbp),%rax
0x403036 <+ 54> 89 10 mov %edx,(%rax)
231 [1] minutes -= 60;
0x403038 <+ 56> 48 8b 45 10 mov 0x10(%rbp),%rax
0x40303c <+ 60> 8b 40 04 mov 0x4(%rax),%eax
0x40303f <+ 63> 8d 50 c4 lea -0x3c(%rax),%edx
0x403042 <+ 66> 48 8b 45 10 mov 0x10(%rbp),%rax
0x403046 <+ 70> 89 50 04 mov %edx,0x4(%rax)
233 [1] return Time(hours, minutes);
0x403049 <+ 73> 48 8b 45 10 mov 0x10(%rbp),%rax
0x40304d <+ 77> 8b 48 04 mov 0x4(%rax),%ecx
0x403050 <+ 80> 48 8b 45 10 mov 0x10(%rbp),%rax
0x403054 <+ 84> 8b 10 mov (%rax),%edx
0x403056 <+ 86> 48 8d 45 f8 lea -0x8(%rbp),%rax
0x40305a <+ 90> 41 89 c8 mov %ecx,%r8d
0x40305d <+ 93> 48 89 c1 mov %rax,%rcx
0x403060 <+ 96> e8 eb fe ff ff callq 0x402f50 <Time::Time(int, int)>
0x403065 <+ 101> 48 8b 45 f8 mov -0x8(%rbp),%rax
234 [1] }
总结下:我们在自定义数据类型的时候,因为前缀(++i)可以返回对象的引用,而后缀(i++)必须返回对象的值,使用导致大对象在保存值的时候产生了较大的复制开销,从而引起效率降低,所以,我们在使用自己定义的数据类型的时候 ,尽可能的使用前缀递增或者递减。