1. 程式人生 > >C++ STL學習之 空間配置器(allocator)

C++ STL學習之 空間配置器(allocator)

標籤(空格分隔): C++ STL

眾所周知,一般情況下,一個程式包括資料結構和相應的演算法,而資料結構作為儲存資料的組織形式,與記憶體空間有著密切的聯絡. 在C++ STL中,空間配置器便是用來實現記憶體空間(一般是記憶體,也可以是硬碟等空間)分配的工具,他與容器聯絡緊密,每一種容器的空間分配都是通過空間分配器alloctor實現的.理解alloctor的實現原理,對記憶體結構以及資料儲存形式會有更清晰直觀的認識.

1.兩種C++類物件例項化方式的異同

在c++中,建立類物件一般分為兩種方式:一種是直接利用建構函式,直接構造類物件,如 Test test();另一種是通過new來例項化一個類物件,如 Test *pTest = new Test;那麼,這兩種方式有什麼異同點呢?

我們知道,記憶體分配主要有三種方式:

(1)靜態儲存區分配:記憶體在程式編譯的時候已經分配好,這塊記憶體在程式的整個執行空間內都存在.如全域性變數,靜態變數等. (2)棧空間分配:程式在執行期間,函式內的區域性變數通過棧空間來分配儲存(函式呼叫棧),當函式執行完畢返回時,相對應的棧空間被立即回收. 主要是區域性變數. (3)堆空間分配:程式在執行期間,通過在堆空間上為資料分配儲存空間,通過malloc和new建立的物件都是從堆空間分配記憶體,這類空間需要程式設計師自己來管理,必須通過free()或者是delete()函式對堆空間進行釋放,否則會造成記憶體溢位.

那麼,從記憶體空間分配的角度來這兩種方式的區別,就比較容易區分:

對於第一種方式來說,是直接通過呼叫Test類的建構函式來例項化Test類物件的,如果該例項化物件是一個區域性變數,則其是在棧空間分配相應的儲存空間. 對於第二種方式來說,就顯得比較複雜.這裡主要以new類物件來說明一下.new一個類物件,其實是執行了兩步操作:首先,呼叫new在堆空間分配記憶體,然後呼叫類的建構函式構造物件的內容;同樣,使用delete釋放時,也是經歷了兩個步驟:首先呼叫類的解構函式釋放類物件,然後呼叫delete釋放堆空間.

2.C++ STL空間配置器實現

很容易想象,為了實現空間配置器,完全可以利用new和delete函式並對其進行封裝實現STL的空間配置器,的確可以這樣.但是,為了最大化提升效率,SGI STL版本並沒有簡單的這樣做,而是採取了一定的措施,實現了更加高效複雜的空間分配策略.由於以上的構造都分為兩部分,所以,在SGI STL中,將物件的構造切分開來,分成空間配置和物件構造兩部分.

記憶體配置操作:alloc::allocate()實現 記憶體釋放操作:alloc::deallocate()實現 物件構造操作: ::construct()實現 物件釋放操作: ::destroy()實現

STL物件構造與釋放結構圖如下所示:

關於物件的構造和釋放的實現,此處buxijia不細講,但其中利用了replacement new技術,單獨說一下.

replacement new技術實際上就是將一個物件構造在指定的記憶體區域中.該記憶體區域可以是靜態資料區,棧空間或者是堆空間,對於記憶體的管理方式不變.如下程式碼說明replacement new的用法.

#include<new.h> Class Test {...}; char *p = (char *)malloc(sizeof(Test)); Test *tp = new(p) Test();//replacement new 關於記憶體空間的配置與釋放,SGI STL採用了兩級配置器:一級配置器主要是考慮大塊記憶體空間,利用malloc和free實現;二級配置器主要是考慮小塊記憶體空間而設計的(為了最大化解決記憶體碎片問題,進而提升效率),採用連結串列free_list來維護記憶體池(memory pool),free_list通過union結構實現,空閒的記憶體塊互相掛接在一塊,記憶體塊一旦被使用,則被從連結串列中剔除,易於維護. free_list的結構如下所示: union obj{ union obj *free_list_link; char client_data[1]; }; free_list的實現技巧如下圖所示:

從free_list取出記憶體塊示意圖:

釋放記憶體塊加入free_list示意圖:

以上內容僅供參考學習,歡迎大家交流討論.轉載請註明出處.

參考資料