您的位置:首页 > 其它

定制new和delete

2016-06-14 10:26 351 查看
在看《effective C++》第8章(定制new和delete)时,发现自己对new和delete理解的并不是那么深刻。

为什么要定制new和delete呢,因为在某些环境下(嵌入式),定制的new和delete效率会更高。

我在之前的文章“重载new和delete检测内存泄漏”中也做过类似的总结。

下面的例子中重载了class-specific new和class-specific delete

  void* T::operator new  ( std::size_t count );

  void T::operator delete  ( void* ptr );

如果想使用定制的new和delete需要继承fixedSizeResourcePool类。  

总内存(使用了栈内存模拟)的大小固定,被平均分配成8个字节大小的内存块,每次new取其中一块,delete回收一块。

还是看代码吧。  

借用《effective C++》Item 50中的一句话:编写一个几乎能工作的自定义内存管理器相当容易,编写一个工作得很好的要困难得多。

#include <cstdio>
using namespace std;

typedef long unsigned int uint32_t;
typedef unsigned char uint8_t;
typedef unsigned char Alignment;
typedef void* MemAddress;

template<typename T, Alignment ALIGNMENT = 8>
class fixedSizeResourcePool
{
public:
//根据输入,初始化一块内存
//iNumOfObjects:内存块数量
//address:内存起始位置
//name_p:内存名字
static void init(const int iNumOfObjects, const MemAddress address, const char * name_p)
{
name_p_ = const_cast<char*>(name_p);

uint8_t* currAddress = reinterpret_cast<uint8_t*>(address);
for (int i = 0; i < iNumOfObjects; i++)
{
//做到8字节对齐,便于CPU快速寻址
const uint8_t alignmentError = reinterpret_cast<uint32_t>(currAddress) %ALIGNMENT;
if (alignmentError != 0)
{
//去除多余位置
currAddress += (ALIGNMENT - alignmentError);
}
//这里将内存分块:内存本身不变,poolInfo_.freeList_p_在变
linkedList* tmp_p = reinterpret_cast<linkedList*>(currAddress);
//point to currAddress address
tmp_p->next_p_ = poolInfo_.freeList_p_;
//poolInfo_.freeList_p_->next_p_ = poolInfo_.freeList_p_;
poolInfo_.freeList_p_ = tmp_p;

printf("init:: poolInfo_.freeList_p_ = %x \n",poolInfo_.freeList_p_);
//将内存块按sizeof(T)的大小分块

currAddress += sizeof(T);
}
poolInfo_.numOfObjects_ = iNumOfObjects;

printf("fixedSizeResourcePool %s initialized with iNumOfObjects: %d, sizeof(T): %d, totalBuffer: %d, Address: 0x%08x, ALIGNMENT: %d \n",
name_p_, iNumOfObjects, sizeof(T), iNumOfObjects * sizeof(T), address, ALIGNMENT);
}
//重载operator new
static void *operator new(uint32_t size) throw()
{
linkedList* tmp_p = poolInfo_.freeList_p_;
if (tmp_p != 0)
{
printf("new:: poolInfo_.freeList_p_ = %x \n",poolInfo_.freeList_p_);
printf("new:: poolInfo_.freeList_p_->next_p_ = %x \n",poolInfo_.freeList_p_->next_p_);
//每次在链表中获取一块fixedSize的内存
poolInfo_.freeList_p_ = poolInfo_.freeList_p_->next_p_;
poolInfo_.numAllocatedObjects_++;
return tmp_p;
}
else
{
printf("no pool resource \n");
return 0;
}
}

//placement new
static void* operator new(uint32_t size, void *p)
{
return p;
}

//重载operator delete
static void operator delete(void * p)
{
//每次在链表中删除一块fixedSize的内存
linkedList* tmp_p = reinterpret_cast<linkedList*> (p);
tmp_p->next_p_ = poolInfo_.freeList_p_;
poolInfo_.freeList_p_ = tmp_p;

poolInfo_.numAllocatedObjects_--;
}

static inline int getNumFreeObjects()
{
return poolInfo_.numOfObjects_ - poolInfo_.numAllocatedObjects_;
}

class linkedList
{
private:
linkedList* next_p_;
friend class fixedSizeResourcePool;
};

struct poolInfo
{
linkedList* freeList_p_; //链表
int numAllocatedObjects_; //已分配内存块
int numOfObjects_; //总内存块
};

private:
static poolInfo poolInfo_;
static char* name_p_;

protected:
fixedSizeResourcePool(void) {};
virtual ~fixedSizeResourcePool() {};

};

template<typename T, Alignment ALIGNMENT>
typename fixedSizeResourcePool<T, ALIGNMENT>::poolInfo fixedSizeResourcePool<T, ALIGNMENT>::poolInfo_ = {0, 0, 0};

template<typename T, Alignment ALIGNMENT>
char* fixedSizeResourcePool<T, ALIGNMENT>::name_p_ = 0;

class myClass: public fixedSizeResourcePool<myClass, 8>
{
public:
myClass():fixedSizeResourcePool<myClass>()
{
}
};

int main()
{

const int num= 10;
//phyMem is sizeof(myClass)*num = 80 byte
//在栈内存的基础上分配内存
char phyMem[sizeof(myClass)*num];
myClass::init(num, phyMem, "phy_Mem" );

myClass *mO = new myClass;
myClass *mO2 = new myClass;

int n = fixedSizeResourcePool<myClass, 8>::getNumFreeObjects();
printf("After new, The memory left = %d \n", n);

delete mO;
delete mO2;
n = fixedSizeResourcePool<myClass, 8>::getNumFreeObjects();
printf("After delete, The memory left = %d \n", n);

}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: