【面經筆記】STL
空間配置器:
為什麼不說allocator是記憶體配置器:空間不一定是記憶體,空間也可以是磁碟或其他儲存介質,你可以寫一個allocator直接向硬碟取空間。
SGI STL的配置器名為alloc,是預設的空間配置器。
雖然也定義了一個符合部分標準的allocator配置器,但只是把C++中new和delete簡單包裝而已,效能不佳。
SGI std::alloc:
new包含了:operator new記憶體配置 和 物件構造 兩個過程。
delete包含了: 物件析構 和 operator delete記憶體釋放
STL 將兩個階段操作區分開來:
記憶體配置由alloc::allocatr()負責,記憶體釋放由alloc::deallocate()負責;
物件構造由construct()負責,物件析構由deallocate()負責。
考慮小型區塊造成的記憶體破碎問題,SGI設計了雙層級配置器
第一級直接使用allocate()呼叫malloc()、deallocate()呼叫free(),使用類似new_handler機制解決記憶體不足,配置無法滿足的問題。
第二級視情況使用不同的策略,當配置區塊大於128bytes時,呼叫第一級配置器,當配置區塊小於128bytes時,採用記憶體池的整理方式:配置器維護16個(128/8)自由連結串列,負責16種小型區塊的此配置能力。記憶體池以malloc配置而得,如果記憶體不足轉第一級配置器處理。
記憶體池
記憶體池管理:每次配置一大塊記憶體,並維護對應之自由連結串列:free_list,下次若還有相同大小的記憶體需求,直接從連結串列中拔出,如果客戶端釋還小額區塊,就由配置器回收到free_list中。為了方便管理,任何小額記憶體需求均上調至8的倍數。
allocator需要維護一個儲存16個空閒塊列表表頭的陣列free_list,陣列元素i是一個指向塊大小為8*(i+1)位元組的空閒塊列表的表頭,一個指向記憶體池起始地址的指標start_free和一個指向結束地址的指標end_free。空閒塊列表節點的結構如下:
union obj
{
union obj *free_list_link;
char client_data[1];
};
這個結構可以看做是從一個記憶體塊中摳出4個位元組大小來,當這個記憶體塊空閒時,它儲存了下個空閒塊,當這個記憶體塊交付給使用者時,它儲存的時使用者的資料
當free_list不夠時,從記憶體池中取新空間為free_list填充新空間。
當記憶體池不夠時,從堆申請新空間。
當堆不夠時,交由第一級配置器使用類似new_handler機制處理。
iterator
traits(萃取)技術:
利用模板的引數推導機制,獲取任意迭代器的特徵資訊:
Template<class T>
Struct iterator_traits
{
Typedef typename T::value_type value_type;
}
如果T定義有自己的value_type,通過traits的作用,萃取出來的就是T::value_type。
這種多了一層間接性的好處是可以擁有原生指標的偏特例化版本:如偏特例化原始指標版本iterator_traits<T*>和iterator_traits<const T*>
。
原生指標int*雖不是一種類型別,亦可通過iterator_traits取其value_type。
序列容器:vector
頻繁對vector呼叫push_back()對效能的影響和原因:
當push_back()將新元素插入vector尾端時,首先檢查是否還有備用空間,如果容量被用完,並不是在原空間後接續新空間,而是以原大小的兩倍重新分配一塊空間,將原內容拷貝過來,並新增上新元素,釋放原空間。
一旦push_back()引起空間重新配置,指向原vector的所有迭代器失效。
序列容器:list
雙向連結串列
STL list是一個環狀雙向連結串列
序列容器:deque 雙向佇列
deque沒有容量(capacity)的概念,動態的以分斷連續空間組合而成,可以隨時增加一段新的空間並連結起來。
deque是由一段一段的連續空間構成,由迭代器維護整體連續的假象
中控器為一個連續陣列空間(對映/map),每個元素都是指標,指向一段連續線性空間(緩衝區),緩衝區大小一致
在deque上排序很慢,可將資料拷貝至vector ,排序後拷貝回deque
容器介面卡:stack 棧
stack底層預設以deque實現,不提供迭代器
stack<int,deque<int>>
stack<int,list<int>>
容器介面卡:queue 佇列
queue底層預設是deque實現,不提供迭代器
queue<int,deque<int>>
queue<int,list<int>>
heap只有演算法,屬於幕後工作者,是優先佇列的助手
容器介面卡:priority queue 優先佇列
優先佇列預設是最大堆實現
最大堆預設是vector實現的完全二叉樹:
priority_queue<int,vector<int>,less<int>>
priority_queue<int,vector<int>,greater<int>>