最近寫的一個程式,為了使介面簡便,在返回字串的時候不得已使用了stl::string,但是又擔心如果此方法被頻繁調用,可能會導致效能問題,於是嘗試用一些底層機制去最佳化stl::string。
stl::string是怎麼實現的呢?腦海中有一個猜想,首先就是這樣:
class string
{
private:
char* m_str;
int m_len;
};
為了驗證這個想法,於是用sizeof(string)將類型的長度打出來看看…………結果讓人大跌眼鏡,還要我不戴眼睛!在GCC中,sizeof(string)=4。怎麼可能嘛?如果就四個位元組,哪裡放長度資訊呢?
再次輸出更多資訊來驗證:
string str = "abcde";
printf("addr=%08x, this=%08x, str=[%s]/n", (unsigned int)str.c_str(), *((unsigned int*)&str), str.c_str());
string自身的四個位元組儲存的內容竟然就是所指向的字串的指標!!!
難道?難道,string在GCC中的實現,就僅僅只是char*,如果調用str.length(),就是悄悄去調用strlen()?
再寫一個輸入記憶體的16進位字串的函數PrintHex(),用這個函數將記憶體中的資訊列印出來,實現如下:void PrintHex(char* Buffer, int Size, FILE* fp =stdout)
...{
fprintf(fp, "===================================================== ");
char* p = NULL;
int i;
for (i=0, p = Buffer; i<Size; i++, p++)
...{
fprintf(fp, "%02x ", (unsigned char)*p);
if (i%16==15)
...{
fprintf(fp, " ");
}
}
fprintf(fp, " ===================================================== ");
}
列印一下記憶體的資訊試試:
string str="abcde";
PrintHex(((char*)str.c_str())-20, 40);
分析16進位字串,大概明白點string的內部了,看懂的部分大約是這樣的:
struct string_buffer
{
int Length;
int Capacity;
int unknown;
char Content[_Capacity]; // _Capacity = Capacity
};
而string只是指向這樣一個記憶體塊的content部分的指標。分配多個string,就會發現這些記憶體塊隔得很近。
以上分析說明:
1、string只是指向字串池中內容部分的一個指標;(將string作為參數或者傳回值,效能都很高,等同於const string&這樣的參數)
2、字串池的塊中緩衝了長度和預留空間等資訊,所以,不要使用C的字串函數來操作string的任何內容,結果可能不一致。
最後,試試在VC中列印:sizeof(string),天哪!28個位元組!微軟的STL實現,不敢恭維啊!