new和delete重载实现的对象池应用

说明

小块内存频繁分配释放的场景可以使用池式组件

链表来管理对象池

提前new一定数量的对象方便大量的push和pop

实现一个队列,其中为队列元素类(内部类)重载new 和 delete运算符来实现对象池,代码如下

#include <iostream>
#include <ctime>
using namespace std;


template<typename T>
class Queue
{
public:
	Queue()
	{
		_front = _rear = new QueueItem();
	}
	~Queue()
	{
		QueueItem* cur = _front;
		while (cur != nullptr)
		{
			_front = _front->_next;
			delete cur;
			cur = _front;
		}
	}

	void push(const T& val)
	{
		// 有了对象池后,这个操作在多数情况下只需要构造而没有分配内存的操作
		QueueItem* item = new QueueItem(val);
		_rear->_next = item;
		_rear = item;
	}
	void pop()
	{
		if (empty())
		{
			return;
		}
		// _front指向队首元素前一个位置
		QueueItem* first = _front->_next;;
		_front->_next = first->_next;
		if (_front->_next == nullptr)
		{
			_rear = _front; // 置空
		}
		delete first;
	}

	T front() const
	{
		return _front->_next->_data;
	}
	bool empty()const { return _front == _rear; }
private:
	// 内部类,队列的元素抽象
	struct QueueItem
	{
		QueueItem(T data = T()) : _data(data), _next(nullptr) {}
		// 给QueueItem提供自定义内存管理
		void* operator new(size_t size)
		{
			// 提前开辟POOL_ITEM_SIZE个对象的空间,不构造
			if (_itemPool == nullptr)
			{
				// 分配字节,如果用new QueueItem会陷入递归调用
				_itemPool = (QueueItem*)new char[POOL_ITEM_SIZE * sizeof(QueueItem)];
				QueueItem* p = _itemPool;
				// 将每个对象空间组织成链表
				// 每次循环跳跃空间大小为sizeof(QueueItem)
				for (; p < _itemPool + POOL_ITEM_SIZE - 1; ++p)
				{
					p->_next = p + 1;
				}
				p->_next = nullptr;
			}
			// 已经有对象池,则从头取出一块对象空间来
			QueueItem* p = _itemPool;
			_itemPool = _itemPool->_next;
			return p;
		}

		void operator delete(void* ptr)
		{
			// 头插法归还空间
			QueueItem* p = (QueueItem*)ptr;
			p->_next = _itemPool;
			_itemPool = p;
		}

		T _data;
		QueueItem* _next;
		static QueueItem* _itemPool; // 指向对象池首个元素的指针
		static const int POOL_ITEM_SIZE = 100000; // 对象池大小
	};

	QueueItem* _front; // 队头不指向具体元素
	QueueItem* _rear;
};

// typename Queue<T>::QueueItem是告知编译器 Queue<T>::QueueItem是类型而不是成员变量,从而把后面*当乘号
template<typename T>
typename Queue<T>::QueueItem *Queue<T>::QueueItem::_itemPool = nullptr;

int main()
{
	clock_t startTime, endTime;
	startTime = clock();//计时开始
	Queue<int> que;
	for (int i = 0; i < 1000000; ++i)
	{
		que.push(i);
		que.pop();
	}
	endTime = clock();
	cout << "The run time is:" << (double)(endTime - startTime) / CLOCKS_PER_SEC * 1000 << "ms" << endl;
	
	return 0;
}

测试结果

未重载new和delete运算符(没有对象池)100w次pushpop所耗费的时间

The run time is:650s

通过重载new 和 delete运算符来实现对象池,对象池底层用链表实现,new给予用户空间对象空间,delete通过链表头插归还对象空间

运行时间为:

The run time is:155ms

可以看出降低了大量的时间耗费,所用时间是原来的1/4

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值