1

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

#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。有一阵子了。

4

2 回答 2

3

我没有看到重载和覆盖这些运算符的巨大好处。

有一点很明显:你无法逃脱它(不是没有工作)。

如果您希望您的所有内存分配都通过一个位置,那么有人搞砸它所需要的就是:

new Foo();

但是,如果您全局覆盖运算符newand delete,它们必须做更多的工作:

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 并删除

在全球范围内。就像在全局命名空间中一样。您将重载粘贴在标题中的某个地方并将其包含在任何地方。

于 2012-07-18T21:50:15.613 回答
2

您可能有一个通用分配器,它被垃圾收集、对齐并具有最大大小限制,这可能是您的规范的限制。如果您使用使用 new/delete 的外部代码,您可以将请求重定向到此分配器作为某种低级/系统内存空间。

此外,我阅读的文章通常以全局运算符作为开始。这是关于该主题的一个很好的stackoverflow帖子

于 2012-07-18T20:45:21.990 回答