原以为足够现代的编译器的优化能力很强,看来我是高估了。GCC 没测过,VC 2008 刚刚被证实了。
pair<int,int> x(rand(), rand()), y(rand(), rand());
for (int i = 0; i < 1000; ++i)
{
if (x < y)
x.first += y.second, y.second -= x.second;
}
// pair.< 的定义
template<class _Ty1, class _Ty2> inline
bool operator<(const pair<_Ty1, _Ty2>& _Left,
const pair<_Ty1, _Ty2>& _Right)
{ // test if _Left < _Right for pairs
return (_Left.first < _Right.first ||
!(_Right.first < _Left.first) && _Left.second < _Right.second);
}
主要是看其中的 if (x < y) 会被优化成什么样子。我原估计的是会在 inline 展开之后,将函数的返回值直接映射到true/false分支,没想到让我大失所望:
; 93 : {
; 94 : if (x < y)
003d2 8b 45 e4 mov eax, DWORD PTR _x$[ebp]
003d5 3b 45 ec cmp eax, DWORD PTR _y$[ebp]
003d8 7c 1c jl SHORT $LN71@TestBoolOp
003da 8b 4d ec mov ecx, DWORD PTR _y$[ebp]
003dd 3b 4d e4 cmp ecx, DWORD PTR _x$[ebp]
003e0 7c 08 jl SHORT $LN70@TestBoolOp
003e2 8b 55 e8 mov edx, DWORD PTR _x$[ebp+4]
003e5 3b 55 f0 cmp edx, DWORD PTR _y$[ebp+4]
003e8 7c 0c jl SHORT $LN71@TestBoolOp
$LN70@TestBoolOp :
003ea c7 85 40 ff ff
ff 00 00 00 00 mov DWORD PTR tv84[ebp], 0
003f4 eb 0a jmp SHORT $LN68@TestBoolOp
$LN71@TestBoolOp :
003f6 c7 85 40 ff ff
ff 01 00 00 00 mov DWORD PTR tv84[ebp], 1
$LN68@TestBoolOp :
00400 0f b6 85 40 ff
ff ff movzx eax, BYTE PTR tv84[ebp]
00407 85 c0 test eax, eax
00409 74 12 je SHORT $LN1@TestBoolOp
; 95 : x.first += y.second, y.second -= x.second;
0040b 8b 4d e4 mov ecx, DWORD PTR _x$[ebp]
0040e 03 4d f0 add ecx, DWORD PTR _y$[ebp+4]
00411 89 4d e4 mov DWORD PTR _x$[ebp], ecx
00414 8b 55 f0 mov edx, DWORD PTR _y$[ebp+4]
00417 2b 55 e8 sub edx, DWORD PTR _x$[ebp+4]
0041a 89 55 f0 mov DWORD PTR _y$[ebp+4], edx
$LN1@TestBoolOp:
; 96 : }
0041d eb a1 jmp SHORT $LN3@TestBoolOp
$LN2@TestBoolOp:
我原乐观地以为编译器的代码不会出现紫色背景的代码,而红色背景的跳转会直接到黄色处,绿色背景的跳转会跳过黄色。是我对编译器要求太高了吗?可是,这样functor在排序、查找等应用中是随处可见的,要浪费多少CPU 啊!真的是硬件水平高了,软件就可以随意挥霍了吗?
与其这样,类似 std::sort 这样的函数还不如不要 inline Compare Functor,直接使用 qsort 算了,还不用那么多的代码膨胀。感觉这样的代码膨胀带来的效益太少了,好像某权威测试对 std::sort 和 qsort 的对简单数据的排序对比说明它仅比 qsort 快 20%~30%。可是在一个典型应用中它带来的代码膨胀恐怕 2000%~3000%都有吧。
现在用习惯了 C++ 的 Template,不用它就感觉不舒服。但是经常一个小规模的 C++ 程序编译出的执行程序就有2~3M,这还是优化过,去掉所有调试信息的。真不知道如何办好!