从 adata 开始的区域为内存块用于存储数据元素的空间,这里将它称为数据空间。该数据空间以数据的大小 nunitsize 划分为存储单位,每个存储单位可以存储一个数据。为了对尚未被分配使用的空闲单位进行识别,需要对他们编织序号。在内存块初始化时要编制序号,当内存块被被释放回内存池时也要为他们编制序号,总之内存池管理系统是按照序号来识别和管理空闲存储单位的,至于那些被应用程序占用的单位,则其序号自然消失和失效,直至被程序释放回内存时再由回收函数重新为其编号。
显然对于 memoryblock 构造函数来讲,除了对 memoryblock 的各个域进行初始化之外,为空闲单位编制序号,即进行空闲单位存储链表的构建就是它的任务。
综上, memoryblock 的构造函数如下
memoryblock(int nunitsize,int nunitamount):nsize(nunitsize * nunitamount),nfree(nunitamount-1),nfirst(1),pnext(NULL) // nunitsize 存储单位的大小 即 sizeof(T) nunitamount 内存块规模 // nfree 空闲存储单位为 nunitamount-1 nfirst 初值为1 pnext指向下一个内存块的指针为NULL { //为空闲区编号 char *ppdata=adata; cout<<"存储区首指针 ppdate ="<<(int*)ppdata<<endl; for(int i=1;i<nunitamount;i++) { //当前存储单位存储下一个可分配单位的序号 (*(unsigned short *)ppdata)=i; cout<<"下一个可分配单位序号: "<<(int)*ppdata<<endl; //移动指针使之指向下一个单位 ppdata+=nunitsize; } cout<<"-------------调用内存块的构造函数-------------------"<<endl; }
因为构造函数的调用发生在用户第一次向内存池请求数据存储单位时,故 存储区域中的第一个存储单位可视为已被分配而不是空闲单位,故需要真正编制序号的是 nunitamount-1个,并且那个用于存储空闲单位链表头部序号的nfirst 也被初始化为1
按照面向对象的方法,用于向系统申请内存的函数 operator new() 也因该重载于类 memoryblock 中,因为c++ 提供的全局 operator new 不再适合本例。
void *operator new(size_t,int nunitsize,int nunitamount) { cout<<"分配内存并创建memoryblock 对象"<<endl; return ::operator new(sizeof(memoryblock)+nunitsize*nunitamount);// 内存空间的长度为 memoryblock 对象加上 存储空间长度总和 }
其析构函数为
void operator delete(void *pblock) //重载 delete 作为内存块的析构函数 { ::operator delete(pblock); cout<<"---------------调用内存块的析构函数----------------"<<endl; }