Effective C++ 10

来源:互联网 发布:浙江大学网络运行中心 编辑:程序博客网 时间:2024/05/23 01:23

10.如果写了operator new,就要同时写operator delete。


为什么要写自己的operator new和delete,首先这不叫重载,这叫隐藏。 new只是用来申请空间,而构造函数是在申请的空间的基础上继续初始化。

为了效率。缺省的operator new 进行内存分配是并不仅仅分配一块所需大小的内存,因为delete释放内存时要知道指针所指向内容的大小,所以,new时会有一个块来储存内存块的大小,而delete时,会根据这个大小来判断删除内存大小。所以当一个类本身很小的时候,这样做,既浪费时间于内存大小的判断,也浪费空间于内存大小的保存。对于某些类较小,且需要一定数量的这些小对象来储存数据时,最好能写一个operator new 来节约空间与时间。

而由于自己的Operator new申请的内存块中没有保存内存块的大小,导致使用缺省的delete时,会导致不可预测的后果。所以若写了operator new ,就必须同时写operator delete。

一般解决方法是 申请一大块内存,作为内存池,将其分为若干块,每块大小正好为储存对象的大小。当前没有被使用时。

尝试将这种固定大小内存的分配器封装起来。

//内存池的实现。class Pool{public:Pool (size_t n,int size);void* alloc(size_t n);//为一个对象分配足够的内存void free(void* p,size_t n);//将p指定的内存返回到内存池。~Pool();//释放内存池中的全部资源private:void* block;const int BLOCK_SIZE;//池内存放块的数量void* list;};Pool::Pool(size_t n,int size):BLOCK_SIZE(size){block = ::operator new(n*size);int i;for(i = 0;i<BLOCK_SIZE -1;i++){*(unsigned int*)((unsigned int)block + n*i) = (unsigned int)block + n*(1+i);}*(unsigned int*)((unsigned int)block + n*i) = 0;list = block;}void* Pool::alloc(size_t n){void* p = list;if(p){//如果自由链表中还有元素,即还有空间list = (void*)*(unsigned int *)list;return p;}else{throw std::bad_alloc();}return p;}void Pool::free(void* p,size_t n){if(0 == p)return;*(unsigned int*)((unsigned int)p) = (unsigned int)list; list = (void*)p;}Pool::~Pool(){delete block;}class A{public:int a;static void* operator new (size_t size);static void operator delete (void* p,size_t size);A(int x){a = x;}private:static Pool memPool;};Pool A::memPool(sizeof(A),10);inline void* A::operator new(size_t size){return memPool.alloc(size);}inline void A::operator delete(void* p,size_t size){memPool.free(p,size);}int main(){A* list[10];for(int i = 0 ; i < 10;i++){list[i] = new A(i);}int i = 0;for(int i = 0 ; i < 10;i++){delete list[i];}i = 1;for(int i = 10 ; i < 20;i++){list[i-10] = new A(i);}for(int i = 0 ; i < 10;i++){delete list[i];}system("pause");}


这是一个内存池的实现,结果感觉虽然实现了内存池的基本功能,但写的不好看。。。譬如一些问题没有解决,如果要求内存大于池的最大容量的处理,以及释放池内元素时,如果重复释放需要进行一些判断此块内存释放已释放。
忽略上面代码,简单分析一下内存池的基本功能:alloc 为对象申请空间的请求提供内存,而free释放对象现在所在的内存。



这里说的写了 operator new 就要写对应的operator delete,因为你在自己写的new中一定会定义一些其他的操作,使的数据的组织结构不是一个简单的new就实现的,可能有多块动态地址,或者可能像内存池中并没有实际的去申请新的空间,所以一定要根据自己写的new中的操作,设计对应的delete操作。



0 0
原创粉丝点击