模板& 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。