7-6 对象池(object_pool)
分数 10
全屏浏览题目
切换布局
作者 王政单位 山东大学
Java有废料回收(GC)的功能,可以回收无法再使用的内存、对象等资源。但C++就要自己负责释放动态分配的资源。身为一名软件开发者,我感到肩上的担子更重了。那么资源管理是怎样实现的呢?我查到一种用空闲链表(free list) 技术实现 对象池(object pool) 的入门级方案。
比方说有容量为C对象池Object pool[C + 1](0号是哑元不用),用空闲链表把它管起来。C++的链表听说要用深受爱戴和尊敬的指针,但指针才刚讲,来不及了,我先用数组索引模拟指针。
建立空闲链表的头索引、后继数组:int head = 1, next[C + 1];
head为0表示没有空闲单元了,否则表示下个空闲单元的索引
初始化:next[1] = 2; next[2] = 3; ... next[C] = 0;
模拟使用:
分配对象:new
如果head == 0,没有可用单元,返回0即可。
如果head != 0,那么用p保存head现值,将head改为next[head],返回p表示可以使用pool[p]对象。
引用对象:ref p
如果p有效(在[1, C]的范围内,并且已经分配)输出ok
否则error
释放对象:delete p
如果p == 0,输出head即可。C/C++都是这样规定,允许free(NULL)或delete nullptr)。
如果p != 0,即请求归还pool[p]单元:
如果p有效(在[1, C]的范围内,并且已经分配),把它放到空闲链表的头部:next[p] = head; head = p;。
无效则输出error
目的:练习数组、循环、事件模拟、空闲链表技术;辅助理解指针。
输入规格
首行设定对象池容量capacity C,C是正整数,小于65536。
后续有若干行的分配、释放请求,处理到EOF为止。请求数量小于65536。
new分配操作
ref x引用x号单元
delete x释放x号单元
输出规格
首行输出:capacity <C> # head=1
之后逐条处理操作:
原样输出操作和参数、空格、#、空格、操作结果
操作结果有以下几种:
分配:new # return <p>, head=<h>输出分配的单元索引p,分配之后的空闲头索引h。
如果没有空闲单元,返回0。
引用:ref <p> # ok或ref <p> # error
释放:
delete <p> # head=<h>,其中p是释放的单元索引,h是调整后的空闲头索引。
如p无效则输出error
样例输入
capacity 2
new
ref 1
new
new
delete 2
ref 2
delete 2
delete 9
delete 0
new
delete 1
new
delete 1
delete 2
样例输出
capacity 2 # head=1
new # return 1, head=2
ref 1 # ok
new # return 2, head=0
new # return 0, head=0
delete 2 # head=2
ref 2 # error
delete 2 # error
delete 9 # error
delete 0 # head=2
new # return 2, head=0
delete 1 # head=1
new # return 1, head=0
delete 1 # head=1
delete 2 # head=2
代码长度限制16 KB
时间限制400 ms
内存限制64 MB
答案
#include<iostream>
#include<vector>
#include <bitset>
using namespace std;
template<typename T>
class ObjectPool
{
private:
vector<T*> pool;
bitset<65537> is_vaid;
int head = 1,C;
vector<int> next;
public:
ObjectPool(int c)
{
C = c;
for (int i = 0; i < c; ++i)
{
next.push_back(i+1);
pool.push_back(new T());
is_vaid[i] = 0;
}
pool.push_back(new T());
next.push_back(0);
}
int createNew()
{
if (head == 0)return 0;
else if (head != 0)
{
int p;
p = head;
head = next[head];
is_vaid[p] = 1;
//printf("\n2\n");
return p;
}
return 0;
}
T* ref(int p)
{
//cout << endl << "h" << endl;
if (p<1 || p>C)return nullptr;
//cout << endl << "h" << endl;
if (is_vaid[p]==1)
{
//cout << endl << pool[p] << endl;
return pool[p];
}
return nullptr;
}
int deleteObject(int p)
{
if (p == 0)return head;
else
{
if (p >= 1 && p <= C && is_vaid[p]==1)
{
next[p] = head;
head = p;
return head;
}
}
return 0;
}
int getHead()
{
//printf("\n1\n");
return head;
}
};
int main()
{
int C,i;
scanf("capacity %d", &C);
ObjectPool<int>* object_pool = new ObjectPool<int>(C);
int* int_ptr=nullptr;
char c;
c = getchar();
while (c != EOF)
{
c = getchar();
switch (c)
{
case 'n':
scanf("ew");
i = object_pool->createNew();
printf("new # return %d, head=%d\n", i, object_pool->getHead());
break;
case 'r':
scanf("ef %d", &i);
int_ptr =object_pool->ref(i);
if (int_ptr == nullptr)
{
printf("ref %d # error\n", i);
}
else
{
printf("ref %d # ok\n", i);
}
break;
case 'd':
scanf("elete %d", &i);
if (object_pool->deleteObject(i) !=0)
{
printf("delete %d # head=%d\n", i, object_pool->getHead());
}
else
{
printf("delete %d # error\n", i);
}
break;
case EOF:
return 0;
}
}
}