zoukankan      html  css  js  c++  java
  • Effective C++ 10

    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操作。



  • 相关阅读:
    Delphi XE4 FireMonkey 开发 IOS APP 发布到 AppStore 最后一步.
    Native iOS Control Delphi XE4
    Delphi XE4 iAD Framework 支持.
    using IOS API with Delphi XE4
    GoF23种设计模式之行为型模式之命令模式
    Android青翼蝠王之ContentProvider
    Android白眉鹰王之BroadcastReceiver
    Android倚天剑之Notification之亮剑IOS
    Android紫衫龙王之Activity
    GoF23种设计模式之行为型模式之访问者模式
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4298121.html
Copyright © 2011-2022 走看看