通用内存池

本文介绍了一种通用内存池的设计方案,利用模板和单例模式管理内存分配与回收,通过自定义的alloc和dealloc函数实现内存的高效利用。以学生类为例,展示了如何在类中提供operator new和operator delete接口,与内存池类交互,实现内存的精细化管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

通用的内存池

 

首先开辟大内存块,以静态链表的形式组织,有好多节点,每个节点分两部分:数据存储使用和内存管理使用

这两部分每次开辟应开辟多少?

假设开辟一个节点: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地址相同,即实现了单例模式

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值