我在《C++ Primer》中学习了一些关于重载new/delete的知识。但是我很好奇:因为默认的new/delete很好,我应该什么时候重载它们?
5 回答
只有当您的班级有特定的内存要求时,您才应该重载它们。例如,如果您想确保所有实例Foo
都从内存池中分配出来。
除了这类事情之外,很少需要超载它们。
在类级别,重载它们的通常原因是使用内存池。这通常仅对将动态分配很多的非常小的类有用;例如,图中的节点之类的东西,池分配器可以显着提高局部性和分配/解除分配速度。
您还可以重载全局 new 和 delete 运算符以使用特殊分配器(例如从内存中的特定区域分配)。然而,这可能很棘手,因为无法在删除表达式中指定附加参数。实际上,当您这样做时,您还必须替换非放置 new 和 delete 运算符,并安排新运算符以某种方式存储找到正确删除器所需的信息。
当然,虽然没有重载,但您可以将全局 new 和 delete 操作符替换为用于收集有关分配和删除信息的操作符,用于调试目的(或者因为您有一些自定义放置 new/delete)。
您不应该对库中的全局 new/delete 做任何事情。由于您所做的任何事情都需要替换非放置表单,因此在库中执行此操作将存在冲突风险(如果用户还需要在其主应用程序中执行此操作)。
此外,如果您创建了一个像TCMalloc这样的自定义分配库,并且您希望new
程序中的所有分配都进入您的库。
在他们的 folly 库中有一个关于Facebook 的 FBVector类型的有趣文档,它解释了为什么他们为向量使用自定义分配器,特别是它允许就地重新分配、优化增长因子以避免 gcc 的分配爬网等等。
一般来说,自己进行分配是个坏主意,因为这是一个复杂的问题,需要做出很多权衡决策。
想到的一些用例:
- 正如@Joachim Pileborg 所说,跟踪内存分配和释放。诸如 valgrind 或 address sanitizer 之类的工具可以为您做到这一点,但您自己这样做只允许针对分配的子集,因此对性能的影响较小
- 使用自定义分配机制,例如生成对齐地址(用于 SSE 或其他硬件要求),或在共享内存中分配,或使用内存池,或在特定地址分配以满足低级驱动程序需求
- 使用与编译器/标准库提供的分配算法不同的分配算法。根据您的分配和线程模式,选择适当的分配策略可能会提高性能。