通用的内存池
首先开辟大内存块,以静态链表的形式组织,有好多节点,每个节点分两部分:数据存储使用和内存管理使用
这两部分每次开辟应开辟多少?
假设开辟一个节点:new 一个 int ,系统计算出是4个字节,传给 size ,
开辟的时候应该是 4+4 (数据存储使用和内存管理使用)
假设现在设计一个学生类,再设计一个内存池类
学生类每次 new student ,在里面提供 operator new , operator delete(在哪个类中 new ,就在哪个类中提供这两个)
针对内存池,是管理内存的。
内存开辟好之后,如何进行管理?
在内存池里面写两个函数,alloc(开辟内存) dealloc(释放内存),对外提供两个接口
使用时,让学生类和内存池类进行交互,operator new 调用 alloc 接口,operator delete 调用 dealloc 接口。然后在 student 里面,针对 student 通过 operator new , operator delete 进行信息交互,间接调用 alloc ,dealloc 操作内存
#include <iostream>
using namespace std;
//通用的内存池与简单内存池的区别:
//通用的内存池把 operator new 函数分离开,内存管理不依赖于具体某个类,达到通用的目标。
const int MEM_SIZE = 10;
template<typename T> //T的类型代表学生类
class MEM_POOL
{
public:
static MEM_POOL<T>* getInstance()//*
//对外提供一个接口 直接返回内存池对象的一个指针或引用
//如果以类类型返回一定有临时对象产生(不满足单例模式要求),所以一定返回指针或引用
//为什么一定要把这个接口写成静态的?
//普通成员方法依赖对象调用, getInstance 接口是生成对象的,调用接口要对象调用,接口不调用生成不了对象
//写成普通成员方法根本调用不了,所以一定要写成摆脱对象调用的静态接口
{
return &mempool;//*
}
void* alloc(size_t size)//这两个函数底层操作一个数据结构,数据结构中节点如何组织?
{
if(pool == NULL)//内存没有开辟或使用完
{
pool = (Node*)new char[(size + 4)*MEM_SIZE]();//size 代表数据域的字节,加4个字节的管理域
Node* pCur = pool;
for(pCur;pCur < pool + MEM_SIZE - 1;pCur++)
{
pCur->pnext = pCur + 1;
}
pCur->pnext = NULL;
}
Node* rt = pool;
pool = pool->pnext;
return rt;
}
void dealloc(void* ptr)
{
if(ptr == NULL)
return;
Node* p = (Node*)ptr;
p->pnext = pool;
pool = p;
}
private:
//将接口屏蔽起来
MEM_POOL(){} //*
MEM_POOL(const MEM_POOL<T>&); //* //拷贝构造函数不需要实现,只需声明即可
class Node //节点的组织
{
public: //公有构造进行初始化
Node(T val) :mdata(val),pnext(NULL){}
public:
T mdata;
Node* pnext;
};
static MEM_POOL<T> mempool; //* //静态成员对象(类中自身的对象)
//static * pool;//这个指针指向未使用部分起始的位置,指针类型如何确定?根据模板和节点确定
static Node* pool;//静态变量必须类外初始化
};
template<typename T>
typename MEM_POOL<T>::Node* MEM_POOL<T>::pool = NULL;
//Node 属于MEM_POOL 作用域下的类型,属于模板类型的前面一定加 typename 关键字,
//pool 属于MEM_POOL 作用域下的成员变量,将其初始化为空
template<typename T>
MEM_POOL<T> MEM_POOL<T>::mempool;//静态成员对象类外初始化,唯一对象生成好了
class Student
{
public:
Student(string name,int age,bool sex):
mname(name),mage(age),msex(sex)
{}
void* operator new(size_t size)
{
return mpool->alloc(size);
}
void operator delete(void* ptr)
{
mpool->dealloc(ptr);
}
private:
string mname;
int mage;
bool msex;
static MEM_POOL<Student>* mpool;//静态变量必须类外初始化
};
//MEM_POOL<Student>* Student::mpool = new MEM_POOL<Student>(); //此时new 根本无法访问构造函数
MEM_POOL<Student>* Student::mpool = MEM_POOL<Student>::getInstance();//通过接口 getInstance 返回唯一对象
int main()
{
Student* pstu1 = new Student("zhang",18,true);
Student* pstu2 = new Student("li",18,false);
Student* pstu3 = new Student("wang",19,true);
Student* pstu4 = new Student("jin",18,true);
MEM_POOL<Student>* pmpool1 = MEM_POOL<Student>::getInstance(); //*
MEM_POOL<Student>* pmpool2 = MEM_POOL<Student>::getInstance(); //*
MEM_POOL<Student>* pmpool3 = MEM_POOL<Student>::getInstance(); //*
MEM_POOL<Student>* pmpool4 = MEM_POOL<Student>::getInstance(); //*
return 0;
}
POOL刚开始为空
往下走一个(逐过程)发现数据域部分存储Student 的对象(里面为空)
Pnext 里面9个结点,1个结点已使用
此时MEM_POOL<Student>::pool 0x00eabfe8 ,向下走,发现改变
说明0x00eabfe8被分配出去
转到pstu2 看一下,发现为0x00eabfe8
依次类推,每个对象被初始化。
整个内存池设计成模板
MEM_POOL<Student> :用 Student 实例化模板 MEM_POOL 生成 MEM_POOL<Student> 类
针对所有的 Student ,都用这个内存池存储的
思考:需不需要将这个类设计成单例模式?
所有的 Student 其实用一个内存池管理就行,所以需要将 MEM_POOL 模板写成单例模式
单例模式的功能:要求整个类只能生成一个对象
单例模式的实现:1.屏蔽类中生成对象的接口(构造函数 和 拷贝函数)
2.类中提供一个接口来生成对象
(在单例模式的实现代码中用//*标识)
单例模式
往下走,发现1-4地址相同,即实现了单例模式