为游戏引擎中的自定义内存分配重载“新”和“删除”有什么好处?

时间:2012-07-18 20:19:41

标签: c++ memory-management game-engine

我正在将我的游戏引擎从Java移植到C ++。我一直在做自定义内存分配器的大量研究,因为我现在需要担心内存管理。我在这个主题上阅读的每篇文章都说你应该重载newdelete运算符。但是,这些重载的运算符通常只委托并调用处理内存分配的自定义函数。此外,通常使用宏,例如:

#define New(className, size, description) customNew(className, size, description, __FILE__, __LINE__)

它甚至从不使用重载的new运算符,只是调用自定义方法。我理解宏是如何有用的,因为你可以很好地获得文件名和行号,但为什么重载newdelete如果在代码中你只是要使用宏New和不是运营商。

此外,当我们的自定义分配器可能想知道其他信息(如描述,文件名和行号)时,覆盖(不重载)默认new似乎毫无意义。我们无法知道标准调用new的信息,也无法以有意义的方式将其委托给customNew

我没有看到重载和覆盖这些运算符的好处是什么。

在我看来,打电话:

customNew(className, size, desc, file, line);

比调用重载的new

更直观
new (size, desc, file, line) className();

最后,如果我要覆盖并超载,那么最好的位置在哪里?每节课这样做是令人讨厌的单调乏味。可以通过命名空间来完成吗?我计划为每个子系统分别设计项目,以便可以独立维护。我如何促进项目之间的覆盖和重载,然后在游戏项目中?请原谅我的C ++ n00bishness。已经有一段时间了。

2 个答案:

答案 0 :(得分:3)

  

我没有看到重载和覆盖这些运算符的好处是什么。

有一个明显的观点:你无法摆脱它(不是没有工作)。

如果您希望所有内存分配都通过一个位置,那么有人可能需要将其搞砸了:

new Foo();

但是,如果您全局覆盖运算符newdelete,则必须执行更多操作:

void * ptr = malloc(sizeof(Foo));
new(ptr) Foo;

还有一点是浩大的大多数C ++程序员习惯于newdelete,他们默认会使用它们。如果你需要他们使用一个功能,这就成了你必须教他们的东西,他们必须学习。如果他们犯了错误并使用标准方式,请参见上文。

哦,然后是语法:

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