我正在将我的游戏引擎从Java移植到C ++。我一直在做自定义内存分配器的大量研究,因为我现在需要担心内存管理。我在这个主题上阅读的每篇文章都说你应该重载new
和delete
运算符。但是,这些重载的运算符通常只委托并调用处理内存分配的自定义函数。此外,通常使用宏,例如:
#define New(className, size, description) customNew(className, size, description, __FILE__, __LINE__)
它甚至从不使用重载的new
运算符,只是调用自定义方法。我理解宏是如何有用的,因为你可以很好地获得文件名和行号,但为什么重载new
和delete
如果在代码中你只是要使用宏New
和不是运营商。
此外,当我们的自定义分配器可能想知道其他信息(如描述,文件名和行号)时,覆盖(不重载)默认new
似乎毫无意义。我们无法知道标准调用new
的信息,也无法以有意义的方式将其委托给customNew
。
我没有看到重载和覆盖这些运算符的好处是什么。
在我看来,打电话:
customNew(className, size, desc, file, line);
比调用重载的new
:
new (size, desc, file, line) className();
最后,如果我要覆盖并超载,那么最好的位置在哪里?每节课这样做是令人讨厌的单调乏味。可以通过命名空间来完成吗?我计划为每个子系统分别设计项目,以便可以独立维护。我如何促进项目之间的覆盖和重载,然后在游戏项目中?请原谅我的C ++ n00bishness。已经有一段时间了。
答案 0 :(得分:3)
我没有看到重载和覆盖这些运算符的好处是什么。
有一个明显的观点:你无法摆脱它(不是没有工作)。
如果您希望所有内存分配都通过一个位置,那么有人可能需要将其搞砸了:
new Foo();
但是,如果您全局覆盖运算符new
和delete
,则必须执行更多操作:
void * ptr = malloc(sizeof(Foo));
new(ptr) Foo;
还有一点是浩大的大多数C ++程序员习惯于new
和delete
,他们默认会使用它们。如果你需要他们使用一个功能,这就成了你必须教他们的东西,他们必须学习。如果他们犯了错误并使用标准方式,请参见上文。
哦,然后是语法:
customNew(className, size, desc, file, line);
那不行。这可能会分配内存,但不构造一个类型。它与malloc
没有什么不同。所以这个名字是谎言;它不是“新的”任何东西。它只是分配。
您需要使用C ++ 11可变参数模板和就地构造来正确执行操作:
template<typename T, typename ...Args>
T *customNew<T>(const char *className, const char *desc, size_t file, size_t line, Args&&... args)
{
void* ptr = allocate_memory(className, sizeof(T), desc, file, line);
return new(ptr) T(std::forward<Args>(args)...);
}
就个人而言,我会说new(...) T(...)
语法比customNew<T>(...)
版本更清晰。很清楚哪些参数转到分配器,哪些参数转到类型本身。它当然更多标准。
但是我在哪里覆盖全局new并删除
全球。与全局命名空间一样。你将重载粘贴在某个地方的标题中并将其包含在任何地方。
答案 1 :(得分:2)
您可能有一个通用分配器,它是垃圾收集,对齐并具有最大大小限制,这可能是您的规范的可能限制。如果使用使用new / delete的外部代码,则可以将请求重定向到此分配器,作为某种低级/系统内存空间。
另外,我读过的文章经常以global operators为开头。关于这个问题,这是一个很好的stackoverflow post。