當前位置:編程學習大全網 - 源碼下載 - sgi的Stl源代碼

sgi的Stl源代碼

說說C++裏的分配器吧。我們知道,C++ STL中定義了很多容器,每個容器的第二個模板參數都是類型分配器。例如,在VC10中,vector類的模板被聲明為:

模板& ltclass _Ty,class _Ax =分配器& lt_ Ty & gt& gt

分類向量

但是,基本上很少有人會定制壹個分配器。第壹,默認分配器就夠了;其次,我真的不知道怎麽用。壹般來說,我們不需要重新定義壹個分配器。定制的方式主要是提高內存分配相關操作的性能。STL的性能已經足夠好了。其實在windows平臺上,new的底層實現是基於C語言的malloc函數;Malloc函數族是基於Windows HeapCreate、HeapAlloc、HeapFree等相關API實現的。(具體可參考% % VSInstallFolder % \ VC \ CRT \ src \ CRT \ src目錄下的heapinit.c、malloc.c、new.cpp等相關函數)。

拋開性能問題,讓我們看看如何實現我們自己的分配器。

在C++ 2003標準文檔中,關於分配器的描述並不多,大概有兩個主要位置:20.1.5分配器要求和20.4.1默認分配器。雖然內容不多,但是足夠我們自己寫分配器了。

根據分配器要求,我們需要提供壹些類型定義:

1:模板& lttypename T & gt

2:類CHxAllocator

3: {

4:公共:

5: // typedefs...

6:typedef T value _ type;

7: typedef value_type*指針;

8: typedef值類型& amp參考;

9: typedef值_類型常量*常量_指針;

typedef value _ type const & ampconst _ reference

11:typedef size _ t size _ type;

12:typedef ptrdiff _ t difference _ type;

13:

14: // rebind...

15:模板& lttypename _ other & gt結構重新綁定{ typedef CHxAllocator & lt_其他& gt其他;};

16: };

這裏有壹點不太好理解:rebind。C++標準中對重新綁定的描述如下:

上表中的成員類模板rebind實際上是壹個typedef模板:如果名稱分配器被綁定到SomeAllocator & ltT & gt,那麽

分配器::重新綁定& ltU & gt* other與SomeAllocator的類型相同& ltU & gt。

妳這話是什麽意思?可以用壹個簡單的例子來說明:

學校學過數據結構,比如棧,單向鏈表,樹。我們來對比壹下棧和列表,看看有什麽大的區別。拋開數據結構的差異,從allocator的角度來看,我們可以發現堆棧存儲的是元素本身,而鏈表實際上並不直接存儲元素本身。要維護壹個列表,我們至少需要壹個名為next的指針。所以,雖然是保存int的列表,但是list

接下來,我們需要提供其他接口。根據默認分配器的描述,我們應該提供以下接口:

指針地址(參考值)常數

常量_指針地址(常量_引用值)

返回val的地址。

指針分配(size_type cnt,CHxAllocator & ltvoid & gt* const _ pointer pHint = 0)分配空間。類似於malloc。PHint可以忽略,主要是為了類庫提高性能。

Void deallocate(指針p,size _ type n)釋放空間,類似於free。

可以分配的最大數量。

Voidconstruct(指針p,const _ referenceval)用val填充地址p指向的空間。您需要使用palcement new來確保調用構造函數。

Void destroy(指針p)銷毀p指向的內存塊的內容,通常通過顯示研究析構函數來執行。

分配器()拋出()

分配器(const_reference)拋出()

模板& lttypename _ other & gt分配器(CHxAllocator & lt_其他& gtconst & amp)扔()

~CHxAllocator() throw()

各種構造函數和析構函數

如何實現這些功能,只需要復制標準庫中的實現即可。如果妳想使用malloc而不用C,妳也可以寫:

1:指針分配(size_type cnt,CHxAllocator & ltvoid & gt* const _ pointer pHint = 0)

2: {

3:un referenced _ PARAMETER(pHint);

4:

5:if(CNT & lt;= 0)

6: {

7:返回0;

8: }

9:

10:void * pMem = nullptr;

11:if(max _ size()& lt;CNT | |(pMem = malloc(CNT * sizeof(value _ type)))= = NULL)

12: {

13:throw STD::bad _ alloc(0);

14: }

15:

16:返回static _ cast & lt指針& gt(pMem);

17: }

18:

19: void deallocate(指針p,size_type)

20: {

21:免費(p);

22: }

23:

24: void構造(指針p,const_reference值)

25: {

26:::new((void *)p)T(val);

27: }

28:

29:無效銷毀(指針p)

30: {

31:p->;~ T();

32: }

基本上,我們只是實現了自己的分配器。此外,除了這些主要的接口函數,您還需要實現比較運算符= =和!=,但是這些字母根據標準文檔直接返回真假。

正如我在開頭所說,重寫分配器的主要目的是改善性。那麽如何才能提高性能呢?直接用Windows的HeapXXXX堆內存API?其實妳自己用的時候會發現性能提升並不明顯。因為通過new,然後通過malloc,最後通過heapaloc,無非就是直接調用heapaloc。如何實現壹個高性能的分配器需要內存池的思想。另外,侯傑的stl源代碼分析,用類似的思路分析了壹個SGI STL實現的alloc。

  • 上一篇:在java編程中用什麽命令來編譯java源文件 可以將源文件編譯成字節碼文件,求答案 。
  • 下一篇:相山火山-侵入雜巖體三維可視化
  • copyright 2024編程學習大全網