stl原始碼剖析讀書筆記之allocator

2021-08-13 11:38:45 字數 3338 閱讀 2398

第二章開始作者定義了乙個簡單的模板類jj::allocator,有allocator的所有介面,包括allocator()deallocate()construct()destroy()四個成員函式 。但是開啟 stl原始碼中的stl_alloc.h,sgi stl用的最多的std::alloc並沒有construct()destroy()成員函式,sgi stl在這一點上沒有遵守stl規範。construct() 和 destroy()被宣告為全域性函式。

construct() 和 destroy() 全域性函式定義於stl_construct.h。construct()呼叫new操作符,沒什麼好說的,這裡主要說說destroy()。

destroy()可以接受乙個指標作為引數,呼叫相應的析構函式,如下所示。

template

inline

void destroy(_tp* __pointer)

template

inline

void _destroy(_tp* __pointer)

這是泛化的函式模板,如果是基本型別的指標,顯然無法呼叫析構函式,書上說有基本型別指標的特化函式模板,但實際上原始碼裡是非模板函式,由於非模板函式優先順序高於模板函式,遇到類似int*的指標編譯器會呼叫非模板函式,並且不做任何操作,如下所示。

inline

void _destroy(char*, char*) {}

inline

void _destroy(int*, int*) {}

inline

void _destroy(long*, long*) {}

inline

void _destroy(float*, float*) {}

inline

void _destroy(double*, double*) {}

destroy()還可以接受兩個iterator引數,來析構乙個區間的所有物件。這就有乙個問題,如果這個區間很大,而每個物件的析構函式都是無關緊要的(即trivial destructor,析構函式裡什麼都不需要做),那麼乙個個呼叫析構函式很影響效率。所以需要判斷,此物件的析構函式是否是non-trivial。

template _forwarditerator>

inline void destroy(_forwarditerator __first, _forwarditerator __last)

template _forwarditerator>

inline void _destroy(_forwarditerator __first, _forwarditerator __last)

/*****************萃取__type_traits::has_trivial_destructor***************/

template _forwarditerator, class

_tp>

inline void

__destroy(_forwarditerator __first, _forwarditerator __last, _tp*)

/*******************如果no-trivial destructor 依次destroy***********************/

template _forwarditerator>

void

__destroy_aux(_forwarditerator __first, _forwarditerator __last, __false_type)

/*****************如果trivial destructor 不做任何操作*************************/

template _forwarditerator>

inline void __destroy_aux(_forwarditerator, _forwarditerator, __true_type) {}

因為要在編譯期就決定是乙個個呼叫析構函式還是什麼都不做,所以不可能用if…else…語法(執行期才去執行),而是依靠template引數推導。如上**,有兩個函式模板__destroy_aux(),最後乙個引數是_false_type還是__true__type決定了destroy()的操作內容,而這個引數又是從type_traits中萃取出來的,在第3點我們就來講講這個type_traits。

這實際上就是泛型程式設計的常用技巧了,編譯期完成的工作不要到執行期再去做,而是依靠template引數推導等技巧來完成類似於if…else…的判斷。

這一部分放在了第三章iterator,在講完了可以萃取特性的iterator_traits後順帶引出可以萃取更多特性的type_traits,更容易讓人理解。不過要在第二章allocator碰到type_traits就要黑人問號了。所以在這裡說明一下。

type_traits就是告訴編譯器以下資訊,這個型別是否一定要執行預設建構函式(has_trivial_default_constructor),是否一定要執行拷貝建構函式( has_trivial_copy_constructor),是否一定要執行賦值運算子(has_trivial_assignment_operator),是否一定要執行析構函式(has_trivial_destructor),是不是pod型別(is_pod_type)。舉乙個char特化模板的例子如下。

struct __true_type ;

struct __false_type ;

__stl_template_null struct __type_traits;

本來我也不太理解為什麼要用兩個struct來表示__false_type__true_type,直到又去回味destroy()原始碼才明白,仔細看以下兩行。

typedef typename __type_traits<_tp>::has_trivial_destructor

_trivial_destructor;

__destroy_aux(__first, __last, _trivial_destructor());

因為是要用template引數推導來確定特化哪乙個__destroy_aux(),所以就需要兩個class object來讓編譯器進行引數推導,於是定義了兩個空的struct。

STL原始碼剖析讀書筆記

一.stl提供六大元件,彼此可以組合套用。1.容器 containers 各種儲存結構,如vector list deque set map,用來存放資料。2.演算法 algorithme 各種常用演算法,如sort search copy erase等。3.迭代器 iterators 扮演容器與演...

STL原始碼剖析讀書筆記之vector

stl原始碼剖析讀書筆記之vector 1.vector概述 vector是一種序列式容器,我的理解是vector就像陣列。但是陣列有乙個很大的問題就是當我們分配 乙個一定大小的陣列的時候,起初 也許我們不會覺得陣列容量太小不合需求,但是隨著資料量的增加,陣列尺寸 大小不再滿足需求,此時我們需要手動...

《STL原始碼剖析》讀書筆記 三

hashtable 非標準 二叉搜尋樹 任何節點最多只能允許兩個子節點 平衡二叉樹 確保整棵樹的深度為o logn 左右子樹的高度最多差1 setmap multiset 特性與用法與set完全相同,唯一的差別在於它允許鍵值重複,插入的時候用的是rb tree的insert equal 而不是ins...