就提高程式的效能/效率而言,上層的平台/架構/演算法/資料結構當然重要,然而也不能忽視代碼本身的效能最佳化,即為了讓編譯器將你寫的進階語言的代碼翻譯成盡量高效的機器代碼,這方面也是我高度興趣的領域,下面就記錄一些improve performance of c++ codes的方方面面,希望從點滴做起,寫出相對高效的c++codes。
條款1:
--------------------------------
Q:建構函式中使用初始化列表(Initialization list)還是賦值(Aassignment)來初始化成員?
A:盡量使用初始化列表。
--------------------------------
測試:
--------------------------------
(測試主要集中於在x86平台上的MS編譯器,且是在開啟編譯器的最大最佳化功能的情況下,一般對應Release模式)
下面看個c++ test program:
//TestClass.h
class A
{
public:
A();
int i;
};
//TestClass.cpp
#include "TestClass.h"
A::A()
{
i = 0;
}
//LGVector.h
#include "TestClass.h"
class LGVector
{
public:
// constructor
LGVector(){};
LGVector(A a);
private:
int i;
A a;
};
//LGVector.cpp
#include "TestClass.h"
// Initializaton list
LGVector::LGVector(A a) : a(a)
{
}
// Assignment
//LGVector::LGVector(A a) : a(a)
//{
// a = a;
//}
//main.cpp
#include "LGVector.h"
int main(int argc, char* argv[])
{
A a1;
a1.i = 10;
LGVector v1(a1);
return 0;
}
下面是LGVector建構函式的x86 Assembly codes:
初時化列表:(x86, VC++ 6.0, Release, Optimization: Maximize)
_a$ = 8
??0LGVector@@QAE@VA@@@Z PROC NEAR ; LGVector::LGVector, COMDAT
; 14 : {
mov eax, ecx
mov ecx, DWORD PTR _a$[esp-4] // 不會調用A的建構函式
mov DWORD PTR [eax+4], ecx
; 15 : }
ret 4
賦值操作:(x86, VC++ 6.0, Release, Optimization: Maximize)
_a$ = 8
??0LGVector@@QAE@VA@@@Z PROC NEAR ; LGVector::LGVector, COMDAT
; 7 : {
push esi
mov esi, ecx
push edi
lea edi, DWORD PTR [esi+4]
mov ecx, edi
call ??0A@@QAE@XZ ; A::A // 會調用A的建構函式,注意:並沒有分配額外的記憶體來創
建額外的對象,只是將當前對象的的子物件a的指標(edi)傳遞到A:A()中,做一些初時化。performance的下降只在於A:A()的調用。
; 8 : this->a = a;
mov eax, DWORD PTR _a$[esp+4]
mov DWORD PTR [edi], eax
; 9 : }
mov eax, esi
pop edi
pop esi
ret 4
--------------------------------
小結:
--------------------------------
VC++ 6.0下:
在建構函式中,推薦使用初時化列表來初始化成員,可以避免成員的建構函式的調用,提高performance,但只針對
non built-in/instinctive types,因為built-in/instinctive types沒有建構函式。
在VC++2005:
貌似兩者performance一樣,賦值操作來初始化成員也不會調用成員的建構函式。
--------------------------------