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



  • 相关阅读:
    cf536c——思路题
    cf536b——优先队列的运用
    王道论坛和九度论坛
    Ubuntu 12.04 LTS 下配置 apache支持SPDY, 使用wireshark 抓包分析SPDY 协议
    vnc/route/ifconfig 配置
    MIME protocol 说明
    理解邮件传输协议(SMTP、POP3、IMAP、MIME)
    GNU C中的零长度数组
    ftp protocol
    HTTP协议头部与Keep-Alive模式详解
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4298121.html
Copyright © 2020-2023  润新知