在《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, 让所有继承该类的子类都具有这种内存池的动态内存分配方式呢?