1. 程式人生 > >【面經筆記】STL

【面經筆記】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>>