STL原始碼剖析 整體簡要概述

2021-06-29 07:37:26 字數 2429 閱讀 8683

stl原始碼剖析—簡要概述

首先需要明白stl內部各個元件以及元件之間的關係,stl號稱是泛型程式設計的典範,泛型程式設計不僅僅是模板的高階應用,這裡更多體現了整體的設計思想。

空間配置器、迭代器、容器、演算法、仿函式、介面卡,共六大元件,其中這裡比較關心的就是前四個。這裡面涉及了模板、模板的偏特化、模板的特化。所有的操作都是為了更高的效率而存在的。

一、空間配置器

對於乙個stl的模板庫來說,空間的分配極其重要,因為所有元素的儲存都需要空間來分配。stl的空間配置器是自己定義的,使用了二級配置的想法,對於申請空間大於128kb的情況使用以及配置,也就是直接使用malloc申請空間,對於申請空間小於128kb的情況使用二級配置,也就是記憶體池的管理,每次配置一大塊記憶體,並維護對應之自由鍊錶,下次若再有相同大小的記憶體需求,就直接從鍊錶中取出,可以將這裡的記憶體池看成使用開鏈法的hashtable,某乙個桶內儲存的都是大小相同的小記憶體塊。

對於常規的記憶體操作new包含兩個階段的操作,呼叫operator new配置記憶體,呼叫物件的建構函式構造物件內容,delete算式也包含兩個階段,呼叫物件的析構函式,呼叫operatordelete釋放記憶體。為了精細分工,stlallocator決定將這兩個階段的操作區分開來,記憶體配置操作由alloc::allocate()負責,記憶體釋放操作由alloc::deallocate()負責,物件構造操作由::constructor()負責,物件析構操作由::destroy()負責。所以從這裡也可以看出來,物件析構並不代表記憶體已經釋放,在有些容器(比如vector)就是這樣的過程,呼叫clear知識容器內的物件呼叫了對應的析構函式,並不代表這塊記憶體已經被釋放掉.

對於destroy()函式也是用了特化的處理,對於有些沒有必要呼叫析構函式的物件就不用呼叫析構函式,當然為了判斷析構函式是否無關緊要,就用到了萃取的功能,value_type()獲得迭代器所指物件的型別,再萃取特性判斷析構函式的性質。記憶體的申請最終封裝成乙個類(******_alloc,在以後的容器中經常會看到對這個類的typedef),類裡面的函式屬性均為static。

為了配合使用,在stl內部還定義了幾個全域性函式用來填充或複製大塊記憶體資料,

uninitialized_copy(),uninitialized_fill()、uninitialized_fill_n()函式

總結:大塊記憶體的申請使用allocate和deallocate(),內部使用的malloc和free,小塊記憶體是從記憶體池中取。物件的構造和析構使用contructor和destroy(),內部使用placement new和呼叫對應的析構函式。為了記憶體更加方便的使用,這裡由新增了幾個全域性的函式,三個全域性的函式對應演算法庫中的copu,fill.fill_n。為了更高效的完成工作,對某些函式使用了模板的特化和泛化。

二、迭代器

迭代器是粘合演算法和容器的樞紐,正是有了迭代器是的演算法和容器相互對立,同時有可以有關聯,對於每一種容器,內部都是相應的迭代器的宣告,這些宣告正是演算法中需要使用的內容,這樣就達到了容器和演算法結合的特性。同時迭代器分為好幾種,比如vector的迭代器就是隨機迭代器,hashtable的迭代器就是前向迭代器,紅黑樹的迭代器是雙向迭代器。迭代器的幾種類別使得演算法中更加好用。同時stl中的萃取使得很多任務作變得很簡單。

三、容器

容器分為序列容器和關聯容器。vector是序列容器的典範,對於申請的記憶體總是不必須要的記憶體少。對於迭代器失效,記憶體連續的失效情況最嚴重,當然遇到記憶體從新分配,都是一樣的效果(關聯容器中以紅黑樹為底層實現的容器是不會出現記憶體重新分配的情況,但是以hashtable為底層實現的關聯容器會出現記憶體重新分配的情況)。vector的clear操作並沒有釋放記憶體,只是呼叫了物件的析構函式。如果記憶體不夠使用,就需要重新分配記憶體(分配的記憶體時原來記憶體大小的兩倍),然後進行搬移,在vector內部沒有push_front的操作。對於vector的inster操作中,如果不重新分配記憶體,也需要看插入點之後的元素和插入元素的個數之間的比較,根據比較的結果來進行如何插入。容器中所有的插入都是指在某一點之間插入。對於雙向鍊錶slist是帶有頭節點的雙向鍊錶,由於是雙向鍊錶,便有push_front,pop_front之說。同時刪除乙個節點就是對這個節點所佔的記憶體空間進行釋放,slist的迭代器提供的雙向迭代器,對於slist內部有自己實現和演算法中的部分函式,例如merge,sort,reverse,clear。內部的transfer函式對是前面幾個函式的基礎。對於stl中的容器來說,如果容器本身實現了函式,就沒有必要使用演算法庫中的函式。deque是雙端佇列,他本身也會可能出現記憶體重新分配的情況,deque迭代器的前置和後置都是相當複雜的。deque的設計和開鏈法的hashtable很相似,中樞管理著記憶體塊,記憶體塊中儲存著資料,deque也屬於非連續記憶體空間,所以deque中也有push_front、pop_front的操作。對於deque呼叫clear,只是刪除了儲存資料的記憶體塊,並沒有將中樞刪除。這裡的前置和後置需要考慮的就是考慮跳躍記憶體塊的情況。關聯式容器以hashtable和rb-tree作為底層實現。

四、演算法

對於演算法的部分,都是以迭代器作為引數,對於某乙個函式的實現可能有不同的過載版本。

STL原始碼剖析

這兩天略讀完了 stl原始碼剖析 之所以是略讀,就是只看大體,不講具現 這個詞在 深度探析c 物件模型 中比較多 已經看過好幾本c 的書了,感覺c 本身設計的博大精深,而c 編譯器就更是乙個神奇的東西,換句話說,你永遠不知道c 編譯器揹著你做了哪些出乎你意料的事 不扯遠了 我主要是想看stl容器的具...

STL原始碼剖析

這兩天略讀完了 stl原始碼剖析 之所以是略讀,就是只看大體,不講具現 這個詞在 深度探析c 物件模型 中比較多 已經看過好幾本c 的書了,感覺c 本身設計的博大精深,而c 編譯器就更是乙個神奇的東西,換句話說,你永遠不知道c 編譯器揹著你做了哪些出乎你意料的事 不扯遠了 我主要是想看stl容器的具...

STL原始碼剖析

花了兩天時間略讀了一下 stl原始碼分析 看了個大體,對於細節並沒有深究。之所以想翻翻這本書,主要是想看看stl中的特性 介面卡的具體實現。看完之後收穫還是蠻大的,模板的各種組合讓我眼前一亮,下面大概總結一些內容。1.記憶體分配 sgi記憶體分配採用兩級實現,對於大記憶體塊的申請 大於128k 由第...