在《Effective C++》(Second Edition)中Item 10 "Write operator delete if you write operator new"中提到一個Memory Pool技術, 並給出一個例子
void *Airplane::operator new(size_t size)
{
if(size != sizeof(Airplane))
return ::operator new(size);
Airplane *p = headOfFreeList;
if(p)
headOfFreeList = p->next;
else
{
Airplane * newBlock = static_cast<Airplane *>(::operator new(BLOCK_SIZE*sizeof(Airplane)));
}
for(int i=1; i<BLOCK_SIZE-1; ++i)
newBlock[i].next = &newBlock[i+1];
newBlock[BLOCK_SIZE-1].next = 0;
p= newBlock;
headOfFreeList = &newBlock[1];
}
書中提到, 用這種技術的好處有二: 一. 節省空間的, 普通的new操作由於需要記住申請的大小, 一般需要更多的空間. 而應用這種技術則不需要額外的空間. 二. 操作速度快, 此種的new和delete操作只是對鏈表的添加和刪除操作, 不需要做真正的系統空間分配, 速度更快.
但明顯, 例子中給出的操作只能針對Airplane類進行操作, 試想, 能不能擴充到對任何類進行這樣的Memory Pool操作呢?
第一想法就是用template.
花了一中午的時間寫了一個CMemoryPool模板類. 如下所示
#ifndef __MEMORYPOOL_H__#define __MEMORYPOOL_H__#include <list>template <class _T>class CMemoryPool {public:CMemoryPool(size_t init_size = 100) : INIT_SIZE(init_size), m_memoryHeadList(5){headOfFreeList = NULL;}~CMemoryPool(){std::list<Envelope *>::iterator iter;for(iter = m_memoryHeadList.begin(); iter != m_memoryHeadList.end(); ++iter){Envelope *block = *iter;::operator delete(block);}}_T *alloc(){Envelope *p = headOfFreeList;if(p)headOfFreeList = p->next;else{const size_t ObjectSize = (sizeof(_T) > sizeof(Envelope)) ? sizeof(_T) : sizeof(Envelope);// 申請空間Envelope *newBlock = static_cast<Envelope *>(::operator new(INIT_SIZE * ObjectSize));// 初始化空閑空間列表for(int i=1; i<INIT_SIZE; ++i)((Envelope *)((char *)newBlock + i * ObjectSize))->next = (Envelope *)((char *)newBlock + (i+1) * ObjectSize);((Envelope*)((char *)newBlock + (INIT_SIZE - 1) * ObjectSize))->next = NULL;// 儲存首址m_memoryHeadList.push_back(newBlock);p = newBlock;headOfFreeList = (Envelope*)((char *)newBlock + ObjectSize);}return (_T *)p;}void free(_T *p){if(p==NULL)return;Envelope *freeBlock = (Envelope *)p;freeBlock->next = headOfFreeList;headOfFreeList = freeBlock;}private:union Envelope{_T *object;union Envelope *next;};const size_t INIT_SIZE;// 預設每次分配多少初始大小的空間Envelope *headOfFreeList; // 當前自由空間首址std::list<Envelope *> m_memoryHeadList; // 申請空間首址向量};#endif // !defined __MEMORYPOOL_H__
此模板類對於內建類型, 可做如下使用.
#include <iostream>#include "MemoryPool.h"int main(){CMemoryPool<double> d_Pool;double *p[10];int i;for(i=0; i<10; ++i){p[i] = d_Pool.alloc();std::cout<<p[i]<<std::endl;}for(i=0; i<5; ++i)d_Pool.free(p[i]);for(i=0; i<5; ++i)p[i] = d_Pool.alloc();for(i=0; i<10; ++i)std::cout<<p[i]<<std::endl;return 0;}
如果僅僅這樣使用, 還沒有達到所要求的目的.
關鍵是對於自己的自訂類, 通過重載operator new與operator delete來使用Memory Pool
如下:
#include <iostream>#include "MemoryPool.h"class MyClass{public:MyClass();~MyClass();static void * operator new(size_t t);static void operator delete(void *p);private:static CMemoryPool<MyClass> st_objectPool;};CMemoryPool<MyClass> MyClass::st_objectPool(10);MyClass::MyClass(){std::cout<<"A() called"<<std::endl;}MyClass::~MyClass(){std::cout<<"~A() called"<<std::endl;}void * MyClass::operator new(size_t t){if(t != sizeof(MyClass))return ::operator new(t);return MyClass::st_objectPool.alloc();}void MyClass::operator delete(void *p){MyClass::st_objectPool.free((MyClass *)p);}int main(){MyClass *ptr;ptr = new MyClass;delete ptr;return 0;}
至此, 已經完成了對於任何類的一個CMemoryPool類的寫法, 自然會想到, 怎麼樣去寫一個基類CMemoryPoolBaseClass, 讓所有繼承該類的子類都具有這種記憶體池的動態記憶體分配方式呢?