侯捷說:追蹤一流程序,并從中吸取養(yǎng)分,模仿著他寫的程序,比那些自以為靠自己努力寫出來的下三流程序價(jià)值高得多,至少我這么認(rèn)為——世界上99.999%的程序,在STL面前都是下三流水平!
?
侯捷老師這句話對(duì)STL的評(píng)價(jià)太高了,以前只是熟練使用STL,知道一點(diǎn)原理,受他的影響,最終還是決定研究STL的源碼,收益頗豐,還是把這個(gè)過程記錄下來,并想著借助標(biāo)準(zhǔn)庫(kù)的原理,自己寫一個(gè)完整的仿STL,我覺得這是一個(gè)很大的工程,因?yàn)樯婕暗礁呒?jí)數(shù)據(jù)結(jié)構(gòu),強(qiáng)大的算法,泛型編程思維,STL的掌握,強(qiáng)大的C++編碼水平,層次復(fù)雜的繼承,型別萃取技術(shù),相信這個(gè)過程會(huì)收益頗豐!畢竟我才大二,時(shí)間一大把,我想在我本科期間,做完這一個(gè)工程,也無憾了!
?
下圖就是STL的層次分布圖,當(dāng)然還缺少一些組件,比如數(shù)值處理,pair對(duì)組,string,智能指針以及valarray數(shù)組等等,其中實(shí)現(xiàn)的難點(diǎn)主要集中在幾個(gè)地方,分別是map紅黑樹的實(shí)現(xiàn),heap算法體系,函數(shù)配接器,流迭代器。尤其是函數(shù)配接器,他的內(nèi)部實(shí)現(xiàn)簡(jiǎn)直是窮盡一切頂尖技巧,令人嘆為觀止,我先從最左邊的內(nèi)存分配器開始,因?yàn)樗撬械暮诵?#xff01;
?
?
首先STL的內(nèi)存分配器(空間配置器)在標(biāo)準(zhǔn)庫(kù)中充當(dāng)了異常重要的角色,所有的內(nèi)存分配,管理,釋放都是由他控制,SGI的設(shè)計(jì)理念就是把內(nèi)存管理這一塊紅燈區(qū)抽離出來,作為模版參數(shù)傳遞進(jìn)去每個(gè)容器,
比如在vector:
template<class T,class Alloc<T> = allocator<T> >
class vector.........
他使用的是內(nèi)置的默認(rèn)內(nèi)存分配器,在上圖中我們看到有兩個(gè)分配器,這是SGI STL中的高級(jí)之處,實(shí)作了多級(jí)內(nèi)存分配,利用內(nèi)存池實(shí)現(xiàn)效率上的優(yōu)化,同時(shí)也減少了內(nèi)存碎片的可能性。
在這之前需要知道兩個(gè)全局函數(shù) ::operator new 和 ::operator delete ,注意不要把他們和一般的new delete混為一談,我們的運(yùn)算符new在分配內(nèi)存的時(shí)候同時(shí)調(diào)用對(duì)象的構(gòu)造函數(shù)初始化內(nèi)存,而::operator new只是分配內(nèi)存,并不調(diào)用構(gòu)造函數(shù),這是實(shí)現(xiàn)一塊無初始化內(nèi)存池的關(guān)鍵點(diǎn),同理delete。
另外還需要了解placement new運(yùn)算符,他是定位運(yùn)算符,并不分配內(nèi)存,只是定位到某一已分配區(qū)域!
這里我們先實(shí)現(xiàn)一個(gè)能跟標(biāo)準(zhǔn)容器接口的分配器類,他并不高明,但是體現(xiàn)了標(biāo)準(zhǔn)分配器的必要特性,其實(shí)從某個(gè)角度說屬于SGI版本的一級(jí)分配器:
[cpp] view plaincopyprint?
template<class?_Ty>??????struct?Allocator_base??????{?????????typedef?_Ty?value_type;??????};????template<class?_Ty>??????struct?Allocator_base<const?_Ty>??????{?????????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);??????}????????????bool?operator==(Allocator?const&?a)?const???????{?return?true;?}????????bool?operator!=(Allocator?const&?a)?const???????{?return?!operator==(a);?}??};????????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://配置器內(nèi)部型別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;//配置器型別轉(zhuǎn)換template<class _other>struct rebind{typedef Allocator<_other> other;};//地址函數(shù)定義pointer address(reference value)const{return &value;}const_pointer address(const_reference value)const{return (const_pointer)&value:}//默認(rèn)構(gòu)造函數(shù) 什么都不干Allocator() throw() {}//默認(rèn)復(fù)制構(gòu)造 Allocator(const Allocator &)throw() {}//不同配置器的復(fù)制構(gòu)造template<class _otherAll>Allocator(const Allocator<_otherAll> &)throw() {}//析構(gòu)函數(shù)~Allocator()throw() {}//返回能分配的最大內(nèi)存size_type max_size()const throw(){ //借助數(shù)值函數(shù)numeric_limit<size_type>::max() /sizeof(_Ty);}//分配未構(gòu)造的內(nèi)存待用pointer allocate(size_type num,typename Allocator<void>::const_pointer hint= 0){return (pointer)(::operator new(num * sizeof(_Ty)) );}//在內(nèi)存中構(gòu)造對(duì)象void construct(pointer p,const_reference value){new(p) _Ty(value);}//析構(gòu)內(nèi)存中的對(duì)象void destroy(pointer p){p->~_Ty();}void deallocate( pointer p, size_type size ){::operator delete(p);}//為了跟標(biāo)準(zhǔn)配置器接軌,這里只能返回true,下一個(gè)只能返回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(){ //復(fù)制構(gòu)造,什么都不干}template<class _Other>Allocator(const Allocator<_Other>&) throw(){ }template<class _Other>Allocator<_Ty>& operator=(const Allocator<_Other>&){ return (*this);}};
最開始是兩個(gè)基類,這兩個(gè)基類沒有任何成員,只有一個(gè)內(nèi)置型別,這兩個(gè)基類不是必須的,可以略過,只是體現(xiàn)一種好的設(shè)計(jì)而已,最后一個(gè)類是模版特化了一個(gè)void類型,這樣做也只是為了使用void的時(shí)候不發(fā)生未定義行為,從這一點(diǎn)可以看到STL對(duì)各種可能的情況都做了充分的預(yù)料,我們主要來看Allocator類!
剛開始定義了一對(duì)typedef,這是為分配器類定義一堆內(nèi)置型別,其實(shí)也可以不定義啊,只不過在STL中都這樣定義,構(gòu)建出一種統(tǒng)一的類型型別,方便管理和可讀性
接下來的
template<class _other>
struct rebind
{
???? typedef Allocator<_other> other;
};
這是一個(gè)分配器轉(zhuǎn)換方式,可以方便的轉(zhuǎn)換為為另一種類型服務(wù)的分配器,比如說我們構(gòu)造的是T類,如果需要構(gòu)造T*的時(shí)候,可以這樣使用
Allocator<T>::rebind<T*>::other? pAllocator;
這樣pAllocator就是一個(gè)為T*服務(wù)的分配器,具體參考《STL標(biāo)準(zhǔn)程序庫(kù)》!
?
該類接下來的函數(shù)都是標(biāo)準(zhǔn)接口必須的,不能少任何一個(gè),其中有變動(dòng)的是這四個(gè) allocate?? deallocate?? destory? construct
allocate函數(shù)分配一片連續(xù)的未被構(gòu)造的空間備用,
deallocate??函數(shù)釋放空間
construct函數(shù)調(diào)用布局new,同時(shí)調(diào)用構(gòu)造函數(shù),對(duì)象被new定位在指定位置
destory?函數(shù)調(diào)用析構(gòu)函數(shù),
之所以說這幾個(gè)函數(shù)可變性比較大,我舉個(gè)例子,假如我們做一個(gè)學(xué)生成績(jī)管理系統(tǒng),當(dāng)然需要構(gòu)造學(xué)生類,也就是需要從數(shù)據(jù)庫(kù)獲得數(shù)據(jù)來初始化學(xué)生對(duì)象,那么你就可以在construct里面內(nèi)嵌SQL語句,在你盛裝學(xué)生對(duì)象的容器中,獲得的數(shù)據(jù)來源不是從鍵盤輸入(參數(shù)傳入),而是自動(dòng)的從數(shù)據(jù)庫(kù)獲取過來,這樣豈不是很方便!同理其他幾個(gè)函數(shù),
這個(gè)分配器還是很簡(jiǎn)單的,就只需要注意那幾點(diǎn),所以我們?cè)趯懽约旱姆峙淦飨M蜆?biāo)準(zhǔn)容器接口時(shí),需要注意這幾點(diǎn)
?
以后還會(huì)使用這個(gè)分配器,直接拿來當(dāng)作SGI STL版本的一級(jí)分配器,至于二級(jí)分配器,下一節(jié)在寫!
到此我們可以寫個(gè)小程序測(cè)試一下了:
[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;
}
?
?
?
?
?
?
總結(jié)
以上是生活随笔為你收集整理的一步一步写STL:空间配置器(1)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。