Why would one replace default new and delete operators?
为什么shouldwould one replace the default operator
这是在非常亮的C++ FAQ中重载新的和删除的继续:运算符重载。
此常见问题的后续条目是:我应该如何编写ISOC++标准一致性自定义EDCOX1、0和EDCOX1?1操作符?
注:答案是基于Scott Meyers更有效的C++的经验教训。(注:这意味着是堆栈溢出的C++FAQ的一个条目。如果你想批评在这个表单中提供一个常见问题解答的想法,那么在meta上发布的开始所有这一切的地方就是这样做的地方。这个问题的答案是在C++聊天室中进行监控的,FAQ的想法一开始就出现了,所以你的答案很可能会被那些想出这个想法的人读到。
可以尝试替换
错误使用
类似地,各种编程错误也会导致数据溢出(在分配的块结束之后写入)和欠载(在分配的块开始之前写入)。重载的操作符
如果您对程序的动态内存使用模式有了很好的了解,您通常会发现自定义版本的operator new和operator delete优于默认版本(性能更快,或者所需内存更少,最多50%)。当然,除非你确定自己在做什么,否则这样做不是一个好主意(如果你不理解其中的复杂性,甚至不要尝试这样做)。好的。要收集使用统计信息,请执行以下操作:
在考虑更换
此外,有时您可能需要收集使用信息,例如:计算类的动态对象数,限制使用动态分配等创建的对象数。好的。
所有这些信息都可以通过替换自定义的
许多计算机体系结构要求将特定类型的数据放在特定类型地址的内存中。例如,体系结构可能要求指针出现在4的倍数(即四字节对齐)的地址上,或者双精度指针必须出现在8的倍数(即八字节对齐)的地址上。不遵守这些约束可能会导致运行时出现硬件异常。其他的架构更为宽泛,并且可能允许它在降低性能的情况下工作。双打的分配。在这种情况下,将默认的操作符
如果您知道特定的数据结构通常一起使用,并且您希望在处理数据时最小化页面错误的频率,那么为数据结构创建一个单独的堆,以便将它们聚集在尽可能少的页面上是有意义的。
有时,您希望运算符new和delete执行编译器提供的版本不提供的操作。例如:您可以编写一个自定义操作符
首先,实际上有许多不同的
首先,有
在这两者之间,重载特定于类的操作符比重载全局操作符要常见得多——对于特定类的内存使用来说,遵循一个足够特定的模式是相当常见的,这样您就可以编写比默认值有实质性改进的操作符。一般来说,在全局的基础上准确预测内存使用情况要困难得多。好的。
可能也值得一提的是,虽然
说到需求,可能值得回顾一下其他的需求1:全局操作符必须是真正的全局的——您不能将一个操作符放在名称空间中,也不能使一个操作符在特定的翻译单元中保持静态。换句话说,只有两个级别可以发生重载:特定于类的重载或全局重载。不允许在"命名空间X中的所有类"或"转换单元Y中的所有分配"等中间点中进行分配。类特定的运算符必须是
在讨论了这些准备工作之后,让我们回到最初的问题,即为什么您希望重载这些运算符。首先,我应该指出,重载全局运算符的原因往往与重载特定于类的运算符的原因大不相同。好的。
因为它更常见,我将首先讨论特定于类的操作符。类特定内存管理的主要原因是性能。这通常有两种形式:要么提高速度,要么减少碎片。内存管理器只处理特定大小的块,因此它可以返回任何可用块的地址,而不是花费任何时间检查块是否足够大,如果块太大则将其拆分为两个等,从而提高了速度。碎片以相同的方式减少(大部分)例如,预分配ng一个足够容纳n个对象的块正好为n个对象提供了所需的空间;分配一个对象的内存值将精确地为一个对象分配空间,而不是多分配一个字节。好的。
导致全局内存管理操作符过载的原因有很多种。其中许多面向调试或检测,例如跟踪应用程序所需的总内存(例如,为移植到嵌入式系统做准备),或者通过显示分配和释放内存之间的不匹配来调试内存问题。另一种常见的策略是在每个请求块的边界前后分配额外的内存,并将独特的模式写入这些区域。在执行结束时(也可能是其他时间),检查这些区域,看代码是否写在分配的边界之外。另一种方法是通过自动化内存分配或删除的某些方面来提高易用性,例如使用自动垃圾收集器。好的。
也可以使用非默认的全局分配器来提高性能。一个典型的例子是替换一个通常速度很慢的默认分配器(例如,至少一些4.x左右的MS VC++版本会为每个分配/删除操作调用系统
好啊。
Many computer architectures require that data of particular types be placed in memory at particular kinds of addresses. For example, an architecture might require that pointers occur at addresses that are a multiple of four (i.e., be four-byte aligned) or that doubles must occur at addresses that are a multiple of eight (i.e., be eight-byte aligned). Failure to follow such constraints can lead to hardware exceptions at run-time. Other architectures are more forgiving, and may allow it to work though reducing the performance.
澄清:如果一个体系结构需要(例如)
另一方面,一些体系结构允许一个或多个数据类型进行不同(或全部)的对齐,但根据相同类型的对齐提供不同的性能保证。然后,一个实现可以返回内存(同样,假设请求的大小合适),该内存是次优化对齐的,并且仍然是一致的。这就是这个例子的内容。
The operator new that ship with some compilers don't guarantee eight-byte alignment for dynamic allocations of doubles.
请给我引文。通常,默认的new操作符只比malloc包装稍微复杂一些,按照标准,malloc包装返回的内存适合于目标体系结构支持的任何数据类型。
我不是说没有充分的理由为自己的类重载new和delete…你已经在这里提到了几个合法的,但上面不是其中之一。
从我的回答中重复"有什么理由使全局新建和删除超负荷?"这里——查看那个答案(或者其他问题的答案),了解更详细的讨论、参考和其他原因。这些原因通常适用于本地运算符重载和默认/全局运算符重载,也适用于c
We overload the global new and delete operators where I work for many
reasons:
- pooling all small allocations -- decreases overhead, decreases fragmentation, can increase performance for small-alloc-heavy apps
- framing allocations with a known lifetime -- ignore all the frees until the very end of this period, then free all of them
together (admittedly we do this more with local operator overloads
than global)- alignment adjustment -- to cacheline boundaries, etc
- alloc fill -- helping to expose usage of uninitialized variables
- free fill -- helping to expose usage of previously deleted memory
- delayed free -- increasing the effectiveness of free fill, occasionally increasing performance
- sentinels or fenceposts -- helping to expose buffer overruns, underruns, and the occasional wild pointer
- redirecting allocations -- to account for NUMA, special memory areas, or even to keep separate systems separate in memory (for e.g.
embedded scripting languages or DSLs)- garbage collection or cleanup -- again useful for those embedded scripting languages
- heap verification -- you can walk through the heap data structure every N allocs/frees to make sure everything looks ok
- accounting, including leak tracking and usage snapshots/statistics (stacks, allocation ages, etc)
我使用它来分配特定共享内存领域中的对象。(这与Russell Borogove提到的类似。)
几年前我为洞穴开发了软件。这是一个多墙虚拟现实系统。它使用一台电脑驱动每个投影仪;最多6台(4个墙壁、地板和天花板),而3台更常见(2个墙壁和地板)。机器通过特殊的共享内存硬件进行通信。
为了支持它,我从我的普通(非cave)场景类派生了一个新的"new",它将场景信息直接放在共享内存领域中。然后我把指针传递给不同机器上的从属渲染器。
与使用统计相关:按子系统预算。例如,在基于控制台的游戏中,您可能需要为3D模型几何保留一些内存片段,一些用于纹理,一些用于声音,一些用于游戏脚本等。自定义分配器可以按子系统标记每个分配,并在超出单个预算时发出警告。