看起来operator new
和operator new[]
具有完全相同的签名:
void* operator new( size_t size );
void* operator new[]( size_t size );
并且完全相同:要么返回指向足够大的原始块(未以任何方式初始化)内存的指针,要么抛出异常。
当我使用operator new
和new
创建对象时,我在内部调用operator new[]
- 当我使用new[]
创建对象数组时。 C ++内部以完全相同的方式调用上述两个特殊函数,我看不出这两个函数如何具有不同的含义。
具有完全相同的签名和完全相同的行为的两个不同功能的目的是什么?
答案 0 :(得分:7)
可以覆盖运算符(对于特定类,或在命名空间内,或全局),如果要以不同于数组分配的方式处理对象分配,则可以提供单独的版本。例如,您可能希望从不同的内存池进行分配。
答案 1 :(得分:7)
我对此有一个相当不错的看法,并且直言不讳,从界面的角度来看,没有理由。
我能想到的唯一可能的原因是允许实现的优化提示,operator new[]
可能被调用以分配更大的内存块;但这是一个真正的,非常脆弱的假设,因为你可以new
一个非常大的结构或new char[2]
,它实际上并不算大。
请注意,operator new[]
不会为数组计数或任何内容添加任何神奇的额外存储空间。 new[]
运算符的工作是计算需要多少开销(如果有的话)并将正确的字节数传递给operator new[]
。
[使用gcc进行的测试表明new[]
不需要额外的存储空间,除非正在构造的数组成员的类型具有非平凡的析构函数。]
从接口和合同的角度来看(除了要求使用正确的相应解除分配函数外)operator new
和operator new[]
是相同的。
答案 2 :(得分:6)
在C ++的设计和演变中(第10.3节),Stroustrup提到如果对象X的new运算符本身用于分配对象X的数组,则X :: operator new()的编写者必须处理也有数组分配,这不是new()的常用用法,增加了复杂性。因此,不考虑使用new()进行数组分配。然后,没有简单的方法为动态数组分配不同的存储区域。解决方案是为数组提供单独的allocator和deallocator方法:new []和delete []。
答案 3 :(得分:5)
一个目的是它们可以由用户单独定义。因此,如果我想将单个堆分配的对象中的内存初始化为0xFEFEFEFE,将堆分配的数组中的内存初始化为0xEFEFEFEF,因为我认为它将帮助我进行调试,那么我可以。
这是否值得,这是另一回事。我想如果你的特定程序主要使用非常小的对象和非常大的数组,那么你可以分配不同的堆,希望这会减少碎片。但同样,您可以识别分配大型数组的类,并为这些类重写operator new[]
。或者operator new
可以根据大小在不同的堆之间切换。
要求的措辞实际上有所不同。一个为任何指定大小的对象分配内存,另一个为任何指定大小的数组分配内存。我认为没有任何区别 - 大小为1的数组肯定与对象具有相同的对齐 - 但我可能会弄错。默认情况下,数组版本返回与对象版本相同的事实强烈暗示没有区别。或者至少对象的对齐要求比阵列上的对齐要求更严格,我无法理解......
答案 4 :(得分:1)
标准说,new T
调用operator new( )
和new T[ ]
会调用operator new[]( )
。如果你愿意,你可以重载它们。我相信它们默认没有区别。标准说它们是可替换的(3.7.3 / 2):
该库提供全局分配和释放功能的默认定义。一些全球性的 分配和释放功能是可替换的(18.4.1)。 C + +程序最多只能提供一个 可替换分配或释放功能的定义。任何这样的函数定义都取代了 库中提供的默认版本(17.4.3.4)。以下分配和释放功能 (18.4)在程序的每个翻译单元中在全局范围内隐式声明
void* operator new(std::size_t) throw(std::bad_alloc); void* operator new[](std::size_t) throw(std::bad_alloc); void operator delete(void*) throw(); void operator delete[](void*) throw();