(C++)STL資料存取效率問題

傅小羊發表於2012-09-05

我們向STL容器中放入資料的時候,會在記憶體中複製一份該資料的內容。這裡“資料”可以代表各種例項化的物件,因為有複製操作,所以會依賴於類的 拷貝建構函式賦值建構函式

     Class Widget {
     Public:
           …
           Widget (const Widget&);
           Widget& operator = (const Widget&);
     };

其實,在寫一個類的時候,哪怕忘了寫這兩個函式,編譯器也會偷偷地為我們新增並實現,但如果我們需要在該函式中實現一些其他功能,我們就得顯示地去實現它們。

假定容器存放以上程式碼中的Widget類,如果其本身所佔記憶體並不大,拷貝及賦值建構函式並不複雜,那整個Copy過程將會是很快的。但如果Widget類擁有多項屬性,其本身就佔有了大量的記憶體空間(這個大量的標準本人尚未研究),又或者自己實現的拷貝及賦值建構函式效率太坑爹,那可以想象,每向容器中存放一個Widget物件,都將會佔用大量的系統資源。

熟悉JAVA開發的朋友知道,JAVA容器類中除存放八種基本資料型別會拷貝一份外,其餘的都存放資料物件的引用(Reference)。在C++中也提倡這樣做,如

vector <Widget*> vWidgets;

該vector容器中存放Widget物件的記憶體地址,但是此時需要注意,容器中存放的指標所指向的物件是有要求的,除非是在某一程式碼段內使用時可以用臨時物件,否則必須是用new關鍵字在堆上建立的物件,而在使用完後還需要對其進行清理。一般這些清理工作都會在物件使用完後進行:

vector <Widget*>::iterator iter;
for (iter = vWidgets.begin (); iter != vWidgets.end (); ++iter) {
    delete (*iter);
}

而如果需要對容器中存放的指標本身進行刪除,這裡恐怕不是三言兩語能講清楚了,其實記住一條:首先得清理指標指向的資料,再來清理指標本身。若弄反了,像什麼迭代器失效、清理錯了物件等一系列問題都有可能產生。這個類似於我們寫這樣的程式碼:

int* p = new int (5);

if (p != NULL) {
    delete p;    // 先清理*p
    p = NULL;  // 再清理p
}

所以在資料物件佔用記憶體較大時,我們可以通過存放其指標來提高效率。

而關於C++容器中對智慧指標的存放,所注意的也頗多,這裡先賣個關子,有興趣的朋友可以先去閱讀《Effective STL》一書。

使用C++中的STL容器,也許一開始會覺得麻煩,不如C#或者JAVA中的安全與方便,但用多了,會覺得它是很靈活的,怎樣去搭配完全可以由你自己控制,用一個詞來形容就是civilized。

深入閱讀:《Effective STL》item 3 : Make copying cheap and correct for objects in containers

《STL原始碼剖析》

關於容器內資料本身的清理: 《Effective STL》 《More Exceptional C++》item 2

相關文章