编译器能否优化后置自增操作符

 如果你要让某个变量的值加1,可以用 i++;  也可以用++i;

通常,编码规范都建议我们如果考虑性能,这种情况下最好用前置自增,因为后置自增会多一无用的复制操作。

但这种做法往往跟我们的习惯不相符,我自己还是看“i++”顺眼一点儿。

 

也许,编译器没那么傻,它们可以根据使用环境优化后置自增,真是这样的话,我们就不必破坏自己的习惯了?

试验一下吧。原始类型的自增操作肯定是可以能被编译器优化的。那么自己写的类的后置自增操作符能否被优化呢?

 

我在VC2008(vc9)里写了下面的代码:

class t_iter
{
public:
 t_iter(void):m_n(0){}
 ~t_iter(void){}
public:
 t_iter & operator ++ (){
  m_n++;
  return *this;
 }
 t_iter operator ++ (int){
  t_iter tempIter = *this;
  m_n++;
  return tempIter;
 }
 int GetValue() const {
  return m_n;
 }
private:
 int m_n;
};

int _tmain(int argc, _TCHAR* argv[])
{
 t_iter iter; 
 iter++;
 return iter.GetValue();
}


代码里面11~15行的“t_iter operator ++ (int)”这个函数就是后置自增操了。t_iter & operator ++ ()是前置操作。

我选了Maximize Speed (/O2)优化选项,也开着“Use Link Time Code Generation (/ltcg)”(其实不开这个也可以的,因为我把t_iter的代码和调用它的main函数写在同一个.cpp文件里了。

打开汇编文件输出选项,并选择Assembly With Source Code (/FAs),build整个程序,就可以看到我们期待的答案了。

编译后产生的汇编文件中main函数的部分如下:

PUBLIC _wmain
; Function compile flags: /Ogtpy
; COMDAT _wmain
_TEXT SEGMENT
_iter$ = -8      ; size = 4
$T12223 = -4      ; size = 4
_argc$ = 8      ; size = 4
_argv$ = 12      ; size = 4
_wmain PROC      ; COMDAT

; 40   : {

 sub esp, 8

; 41   : 
; 42   :  t_iter iter; 
; 44   :  iter++;

 lea eax, DWORD PTR $T12223[esp+8] ;准备存放后置自增函数的返回值
 lea edx, DWORD PTR _iter$[esp+8] 
 mov DWORD PTR _iter$[esp+8], 0
 call ??Et_iter@@QAE?AV0@H@Z  ; t_iter::operator++ 调用后置自增函数

; 48   :  return iter.GetValue();

 mov eax, DWORD PTR _iter$[esp+8]
 add esp, 8
 ret 0
_wmain ENDP
_TEXT ENDS
END

看第22行,编译器并没有把t_iter的后置自增函数内嵌到main函数中,而是在main函数中调用了后置自增函数,那么就不可能对这个进行优化了。


汇编文件中后置自增函数的部分如下:

;	COMDAT ??Et_iter@@QAE?AV0@H@Z
_TEXT	SEGMENT
??Et_iter@@QAE?AV0@H@Z PROC				; t_iter::operator++, COMDAT
; _this$ = edx
; ___$ReturnUdt$ = eax

; 20   : 
; 21   : 		t_iter tempIter = *this;

	mov	ecx, DWORD PTR [edx]
	mov	DWORD PTR [eax], ecx			;准备好返回值,这条指令显然在单纯的自增调用中是无用的

; 22   : 		m_n++;

	inc	ecx
	mov	DWORD PTR [edx], ecx

; 23   : 		return tempIter;
; 24   : 	}

	ret	0
??Et_iter@@QAE?AV0@H@Z ENDP				; t_iter::operator++
_TEXT	ENDS



我感到奇怪的是,编译器并没有把这个后置自增函数内嵌到调用函数中。我还试了在函数声明前加上__inline和 __forceinline,编译器依然无动于衷,始终不真的inline这个函数。我把operator ++ (int)改成一个普通函数,仍然无济于事。

无奈,我们使用自增函数的时候还是应该养成使用前置自增的习惯。当然,如果我们始终能分清我们要自增的变量是原始类型变量还是对象,那么我们可以选择在简单变量上按照顺眼的标准继续使用 i++,而在对象上使用 ++iterator;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值