日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

一步一步写STL:空间配置器(1)

發布時間:2025/3/15 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一步一步写STL:空间配置器(1) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
侯捷說:追蹤一流程序,并從中吸取養分,模仿著他寫的程序,比那些自以為靠自己努力寫出來的下三流程序價值高得多,至少我這么認為——世界上99.999%的程序,在STL面前都是下三流水平!

?

侯捷老師這句話對STL的評價太高了,以前只是熟練使用STL,知道一點原理,受他的影響,最終還是決定研究STL的源碼,收益頗豐,還是把這個過程記錄下來,并想著借助標準庫的原理,自己寫一個完整的仿STL,我覺得這是一個很大的工程,因為涉及到高級數據結構,強大的算法,泛型編程思維,STL的掌握,強大的C++編碼水平,層次復雜的繼承,型別萃取技術,相信這個過程會收益頗豐!畢竟我才大二,時間一大把,我想在我本科期間,做完這一個工程,也無憾了!

?

下圖就是STL的層次分布圖,當然還缺少一些組件,比如數值處理,pair對組,string,智能指針以及valarray數組等等,其中實現的難點主要集中在幾個地方,分別是map紅黑樹的實現,heap算法體系,函數配接器,流迭代器。尤其是函數配接器,他的內部實現簡直是窮盡一切頂尖技巧,令人嘆為觀止,我先從最左邊的內存分配器開始,因為他是所有的核心!

?

?

首先STL的內存分配器(空間配置器)在標準庫中充當了異常重要的角色,所有的內存分配,管理,釋放都是由他控制,SGI的設計理念就是把內存管理這一塊紅燈區抽離出來,作為模版參數傳遞進去每個容器,

比如在vector:

template<class T,class Alloc<T> = allocator<T> >

class vector.........

他使用的是內置的默認內存分配器,在上圖中我們看到有兩個分配器,這是SGI STL中的高級之處,實作了多級內存分配,利用內存池實現效率上的優化,同時也減少了內存碎片的可能性。

在這之前需要知道兩個全局函數 ::operator new 和 ::operator delete ,注意不要把他們和一般的new delete混為一談,我們的運算符new在分配內存的時候同時調用對象的構造函數初始化內存,而::operator new只是分配內存,并不調用構造函數,這是實現一塊無初始化內存池的關鍵點,同理delete。

另外還需要了解placement new運算符,他是定位運算符,并不分配內存,只是定位到某一已分配區域!

這里我們先實現一個能跟標準容器接口的分配器類,他并不高明,但是體現了標準分配器的必要特性,其實從某個角度說屬于SGI版本的一級分配器:

[cpp] view plaincopyprint?
  • template<class?_Ty>??
  • ????struct?Allocator_base??
  • ????{???//配置器基類??
  • ????typedef?_Ty?value_type;??
  • ????};??
  • ??
  • template<class?_Ty>??
  • ????struct?Allocator_base<const?_Ty>??
  • ????{???//配置器特化于const的基類??
  • ????typedef?_Ty?value_type;??
  • ????};??
  • ??
  • template<class?_Ty>??
  • class?Allocator??
  • ????????:public?Allocator_base<_Ty>??
  • {??
  • public:??
  • ????//配置器內部型別??
  • ????typedef?typename?std::size_t?size_type;??
  • ????typedef?typename?std::ptrdiff_t?difference_type;??
  • ????typedef?_Ty*?pointer;??
  • ????typedef?const?_Ty*?const_pointer;??
  • ????typedef?_Ty&?reference;??
  • ????typedef?const?_Ty&?const_reference;??
  • ????typedef?Allocator_base<_Ty>?_Mybase;??
  • ????typedef?typename?_Mybase::value_type?value_type;??
  • ??
  • ????//配置器型別轉換??
  • ????template<class?_other>??
  • ????struct?rebind??
  • ????{??
  • ????????typedef?Allocator<_other>?other;??
  • ????};??
  • ??
  • ????//地址函數定義??
  • ????pointer?address(reference?value)const{??
  • ????????return?&value;??
  • ????}??
  • ????const_pointer?address(const_reference?value)const{??
  • ????????return?(const_pointer)&value:??
  • ????}??
  • ??
  • ????//默認構造函數?什么都不干??
  • ????Allocator()?throw()?{}??
  • ????//默認復制構造???
  • ????Allocator(const?Allocator?&)throw()?{}??
  • ????//不同配置器的復制構造??
  • ????template<class?_otherAll>??
  • ????Allocator(const?Allocator<_otherAll>?&)throw()?{}??
  • ??
  • ????//析構函數??
  • ????~Allocator()throw()?{}??
  • ??????
  • ????//返回能分配的最大內存??
  • ????size_type?max_size()const?throw()??
  • ????{???//借助數值函數??
  • ????????numeric_limit<size_type>::max()?/sizeof(_Ty);??
  • ????}??
  • ????//分配未構造的內存待用??
  • ????pointer?allocate(size_type?num,??
  • ????????typename?Allocator<void>::const_pointer?hint=?0)??
  • ????{??
  • ????????return?(pointer)(::operator?new(num?*?sizeof(_Ty))?);??
  • ????}??
  • ????//在內存中構造對象??
  • ????void?construct(pointer?p,const_reference?value)??
  • ????{??
  • ????????new(p)?_Ty(value);??
  • ????}??
  • ????//析構內存中的對象??
  • ????void?destroy(pointer?p)??
  • ????{??
  • ????????p->~_Ty();??
  • ????}??
  • ??
  • ????void?deallocate(?pointer?p,?size_type?size?)??
  • ????{??
  • ????????::operator?delete(p);??
  • ????}??
  • ????//為了跟標準配置器接軌,這里只能返回true,下一個只能返回false??
  • ????bool?operator==(Allocator?const&?a)?const???
  • ????{?return?true;?}??
  • ??
  • ????bool?operator!=(Allocator?const&?a)?const???
  • ????{?return?!operator==(a);?}??
  • };??
  • ??
  • ??
  • //allocator模版特化于類型void的類??
  • template<>?class?Allocator<void>??
  • {??
  • public:??
  • ????typedef?void?_Ty;??
  • ????typedef?_Ty*?pointer;??
  • ????typedef?const?_Ty*?const_pointer;??
  • ????typedef?_Ty?value_type;??
  • ??
  • ????template<class?_other>??
  • ????struct?rebind??
  • ????{??
  • ????????typedef?Allocator<_other>?other;???
  • ????};??
  • ??
  • ????Allocator()throw()???
  • ????{?//還是一樣,什么都不干??
  • ????}??
  • ??
  • ????Allocator(const?Allocator<_Ty>&?)throw()??
  • ????{?//復制構造,什么都不干??
  • ????}??
  • ??
  • ????template<class?_Other>??
  • ????????Allocator(const?Allocator<_Other>&)?throw()??
  • ????????{?????
  • ????????}??
  • ????template<class?_Other>??
  • ????????Allocator<_Ty>&?operator=(const?Allocator<_Other>&)??
  • ????????{?????
  • ????????return?(*this);??
  • ????????}??
  • ??
  • };??
  • template<class _Ty>struct Allocator_base{ //配置器基類typedef _Ty value_type;};template<class _Ty>struct Allocator_base<const _Ty>{ //配置器特化于const的基類typedef _Ty value_type;};template<class _Ty> class Allocator:public Allocator_base<_Ty> { public://配置器內部型別typedef typename std::size_t size_type;typedef typename std::ptrdiff_t difference_type;typedef _Ty* pointer;typedef const _Ty* const_pointer;typedef _Ty& reference;typedef const _Ty& const_reference;typedef Allocator_base<_Ty> _Mybase;typedef typename _Mybase::value_type value_type;//配置器型別轉換template<class _other>struct rebind{typedef Allocator<_other> other;};//地址函數定義pointer address(reference value)const{return &value;}const_pointer address(const_reference value)const{return (const_pointer)&value:}//默認構造函數 什么都不干Allocator() throw() {}//默認復制構造 Allocator(const Allocator &)throw() {}//不同配置器的復制構造template<class _otherAll>Allocator(const Allocator<_otherAll> &)throw() {}//析構函數~Allocator()throw() {}//返回能分配的最大內存size_type max_size()const throw(){ //借助數值函數numeric_limit<size_type>::max() /sizeof(_Ty);}//分配未構造的內存待用pointer allocate(size_type num,typename Allocator<void>::const_pointer hint= 0){return (pointer)(::operator new(num * sizeof(_Ty)) );}//在內存中構造對象void construct(pointer p,const_reference value){new(p) _Ty(value);}//析構內存中的對象void destroy(pointer p){p->~_Ty();}void deallocate( pointer p, size_type size ){::operator delete(p);}//為了跟標準配置器接軌,這里只能返回true,下一個只能返回falsebool operator==(Allocator const& a) const { return true; }bool operator!=(Allocator const& a) const { return !operator==(a); } };//allocator模版特化于類型void的類 template<> class Allocator<void> { public:typedef void _Ty;typedef _Ty* pointer;typedef const _Ty* const_pointer;typedef _Ty value_type;template<class _other>struct rebind{typedef Allocator<_other> other; };Allocator()throw() { //還是一樣,什么都不干}Allocator(const Allocator<_Ty>& )throw(){ //復制構造,什么都不干}template<class _Other>Allocator(const Allocator<_Other>&) throw(){ }template<class _Other>Allocator<_Ty>& operator=(const Allocator<_Other>&){ return (*this);}};


    最開始是兩個基類,這兩個基類沒有任何成員,只有一個內置型別,這兩個基類不是必須的,可以略過,只是體現一種好的設計而已,最后一個類是模版特化了一個void類型,這樣做也只是為了使用void的時候不發生未定義行為,從這一點可以看到STL對各種可能的情況都做了充分的預料,我們主要來看Allocator類!

    剛開始定義了一對typedef,這是為分配器類定義一堆內置型別,其實也可以不定義啊,只不過在STL中都這樣定義,構建出一種統一的類型型別,方便管理和可讀性

    接下來的

    template<class _other>

    struct rebind

    {

    ???? typedef Allocator<_other> other;

    };

    這是一個分配器轉換方式,可以方便的轉換為為另一種類型服務的分配器,比如說我們構造的是T類,如果需要構造T*的時候,可以這樣使用

    Allocator<T>::rebind<T*>::other? pAllocator;

    這樣pAllocator就是一個為T*服務的分配器,具體參考《STL標準程序庫》!

    ?

    該類接下來的函數都是標準接口必須的,不能少任何一個,其中有變動的是這四個 allocate?? deallocate?? destory? construct

    allocate函數分配一片連續的未被構造的空間備用,

    deallocate??函數釋放空間

    construct函數調用布局new,同時調用構造函數,對象被new定位在指定位置

    destory?函數調用析構函數,

    之所以說這幾個函數可變性比較大,我舉個例子,假如我們做一個學生成績管理系統,當然需要構造學生類,也就是需要從數據庫獲得數據來初始化學生對象,那么你就可以在construct里面內嵌SQL語句,在你盛裝學生對象的容器中,獲得的數據來源不是從鍵盤輸入(參數傳入),而是自動的從數據庫獲取過來,這樣豈不是很方便!同理其他幾個函數,

    這個分配器還是很簡單的,就只需要注意那幾點,所以我們在寫自己的分配器希望和標準容器接口時,需要注意這幾點

    ?

    以后還會使用這個分配器,直接拿來當作SGI STL版本的一級分配器,至于二級分配器,下一節在寫!

    到此我們可以寫個小程序測試一下了:

    [cpp] view plaincopyprint?
  • #include?<iostream>??
  • #include?<list>??
  • #include?<vector>??
  • #include?<algorithm>??
  • #include?"allocator.h"??
  • using?namespace?std;??
  • ??
  • int?_tmain(int?argc,?_TCHAR*?argv[])??
  • {??
  • ????std::vector<double,Allocator<double>?>?vec_double;??
  • ????std::list<int,Allocator<int>?>?list_int;??
  • ????for(int?i=0;i<60;i++)??
  • ????{??
  • ????????list_int.push_back(i);??
  • ????????vec_double.push_back(?double(i)/3?);??
  • ????}??
  • ??????
  • ????list<int,Allocator<int>?>::iterator?it?=?list_int.begin();??
  • ????vector<double,Allocator<double>?>::iterator?io?=?vec_double.begin();??
  • ??
  • ????cout<<"list?test:"<<endl;??
  • ????for(;?it!=?list_int.end();++it)??
  • ????????cout<<*it<<"?";??
  • ????cout<<endl<<endl;??
  • ??
  • ????cout<<"vector?test:"<<endl;??
  • ????for(;io!=?vec_double.end();++io)??
  • ????????cout<<*io<<"?";??
  • ??
  • ????system("pause");??
  • ????return?0;??
  • }??
  • #include <iostream> #include <list> #include <vector> #include <algorithm> #include "allocator.h" using namespace std;int _tmain(int argc, _TCHAR* argv[]) {std::vector<double,Allocator<double> > vec_double;std::list<int,Allocator<int> > list_int;for(int i=0;i<60;i++){list_int.push_back(i);vec_double.push_back( double(i)/3 );}list<int,Allocator<int> >::iterator it = list_int.begin();vector<double,Allocator<double> >::iterator io = vec_double.begin();cout<<"list test:"<<endl;for(; it!= list_int.end();++it)cout<<*it<<" ";cout<<endl<<endl;cout<<"vector test:"<<endl;for(;io!= vec_double.end();++io)cout<<*io<<" ";system("pause");return 0; }



    ?

    ?

    ?

    ?

    ?

    ?

    總結

    以上是生活随笔為你收集整理的一步一步写STL:空间配置器(1)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。