我正在制作一个小型游戏引擎,并且需要一个与之关联的内存池。 我的问题是,我如何实际分享那些拥有自己课程的用户的内存?
例如,我有一个用户在他的游戏中获得了这个课程;
class Monkey : public GameObject {
public:
Monkey();
~Monkey();
void Eat();
void Sleep();
unsigned long size();
private:
int health;
};
我有一个基类,目前只返回派生类的大小。我想这需要知道这将占用多少空间。
public GameObject {
public:
virtual unsigned long size()=0;
};
他想在我的内存池中分配这个类的新实例。 我不知道编译时的类定义,所以我无法弄清楚实际的方法调用是什么样的。他无法传递一个继承自GameObject的对象,因为这意味着他已经分配了它,这违背了预先分配的内存池的目的。那么如何保留内存实际上适用于任何仲裁类实例?
对不起,如果不清楚
答案 0 :(得分:4)
Memory pools仅允许分配固定大小。因此,如果您尝试使用一个对象分配可变大小的对象,则分配的固定大小是您可以分配的最大大小。
如果要重载分配行为,则需要在基类上重载operator new/delete
。如果用户尝试分配超出内存池最大大小的类型,则应throw std::bad_alloc
。此外,您应该将operator new[]/delete[]
重载为throw std::bad_alloc
,因为分配这些数组可能不是一个好主意。
重载的operator new/delete
将被赋予其正在分配的类型的适当大小。除非用户覆盖它,否则所有派生类都将继承重载的运算符。如果他们这样做......打击他们。
重载本身很简单:
public GameObject {
public:
void *operator new(size_t size);
void operator delete(void *memory);
};
您将通过调用池来获取内存块或释放内存块来实现这些。
答案 1 :(得分:1)
您的内存池将提供用于分配内存的API,您将实现使用池作为基类的operator new
静态成员函数,或者使客户端使用placement new来构造他们想要的任何内存对象在你的游泳池中分配。
在第一种情况下,分配和销毁将完全正常,因为标准new
运营商和delete
运营商最终会调用您的自定义operator new
和operator delete
。所以它应该对您的客户完全透明。但是,只有该继承层中的对象才能在池中分配。
第二种方法略有不同,因为它需要客户的参与。他们要么必须分配/释放内存并手动构造/销毁对象(这很困难且不安全),要么他们会使用带有自定义删除器的智能指针来销毁对象并释放内存。使用此方法,客户端可以在池中放置他们想要的任何内容,包括不从任何内容继承的类型,例如大量的双精度数组。
答案 2 :(得分:0)
让您的游泳池充当malloc。使用placement new:
构造池外部的对象object1* x = new (alloc()) object1();
object2* y = new (alloc()) object2();
x->~object1(); free(x);
y->~object2(); free(y);
// this can (and should) be wrapped in functions, such as operator new/delete
有更好的方法可以做到这一点,但这可以在池中使用,而不知道你的类的声明。
答案 3 :(得分:0)
KaiserJohann ,您似乎指定的是一个允许动态分配可变大小元素的系统。这几乎是对动态分配器的请求。
以下是关于Dynamic/Pool Hybrid Allocation的文章,它可以帮助您解决问题。