简体   繁体   English

为什么:: operator new就足够了,为什么:: operator new []是必要的?

[英]Why is ::operator new[] necessary when ::operator new is enough?

As we know, the C++ standard defines two forms of global allocation functions: 众所周知,C ++标准定义了两种形式的全局分配函数:

void* operator new(size_t);
void* operator new[](size_t);

And also, the draft C++ standard (18.6.1.2 n3797) says: 而且,C ++标准草案(18.6.1.2 n3797)指出:

227) It is not the direct responsibility of operator new or operator delete to note the repetition count or element size of the array. 227)注意数组的重复计数或元素大小不是操作员new或操作员删除的直接责任。 Those operations are performed elsewhere in the array new and delete expressions. 这些操作在数组new和delete表达式中的其他位置执行。 The array new expression, may, however, increase the size argument to operator new to obtain space to store supplemental information. 但是,数组new表达式可能会增加new运算符的size参数,以获取存储补充信息的空间。

What makes me confused is: 让我感到困惑的是:

What if we remove void* operator new[](size_t); 如果我们删除void* operator new[](size_t);怎么void* operator new[](size_t); from the standard, and just use void* operator new(size_t) instead? 从标准,并且只是使用void* operator new(size_t)代替? What's the rationale to define a redundant global allocation function? 定义冗余全局分配函数的理由是什么?

I think ::operator new[] may have been useful for fairly specialized systems where "big but few" arrays might be allocated by a different allocator than "small but numerous" objects. 我认为::operator new[]对于相当专业的系统可能很有用,在该系统中,“大而少”的数组可能由与“小而众”的对象不同的分配器分配。 However, it's currently something of a relic. 但是,目前它是遗物。

operator new can reasonably expect that an object will be constructed at the exact address returned, but operator new[] cannot. operator new可以合理地期望将在返回的确切地址处构造一个对象,而operator new[]则不能。 The first bytes of the allocation block might be used for a size "cookie", the array might be sparsely initialized, etc. The distinction becomes more meaningful for member operator new , which may be specialized for its particular class. 分配块的第一个字节可能用于大小“ cookie”,数组可能被稀疏初始化,等等。这种区别对于成员operator new变得更有意义,后者可能专用于其特定类。

In any case, ::operator new[] cannot be very essential, because std::vector (via std::allocator ), which is currently the most popular way to obtain dynamic arrays, ignores it. 无论如何, ::operator new[]并不是必不可少的,因为std::vector (通过std::allocator )是当前最常用的获取动态数组的方式,它会忽略它。

In modern C++, custom allocators are generally a better choice than customized operator new . 在现代C ++中,自定义分配器通常比自定义operator new更好。 Actually, new expressions should be avoided entirely in favor of container (or smart-pointer, etc) classes, which provide more exception safety. 实际上,应该完全避免使用支持容器(或智能指针等)类的new表达式,因为此类提供了更多的异常安全性。

The standard (n3936) makes it clear that these two operators serve different but related purposes. 该标准(n3936)清楚地表明这两个运算符服务于不同但相关的目的。

operator new calls the function void* operator new(std::size_t) . operator new调用函数void* operator new(std::size_t) The first argument must be identical to the argument to the operator. 第一个参数必须与运算符的参数相同。 It returns a block of storage suitably aligned, and which may be somewhat larger than required. 它返回一个适当对齐的存储块,它可能比所需的存储块大一些。

operator new[] calls the function void* operator new[](std::size_t) . operator new[]调用函数void* operator new[](std::size_t) The first argument may be larger than the argument supplied to the operator, to provide extra storage space if required for array indexing. 第一个参数可能大于提供给运算符的参数,以在数组索引需要时提供额外的存储空间。 The default implement for both is to simply call malloc(). 两者的默认实现都是简单地调用malloc()。

The purpose of operator new[] is to support specialised array indexing, if available. operator new[]的目的是支持特殊的数组索引(如果有)。 It has nothing to do with memory pools or anything else. 它与内存池或其他无关。 In a conforming implementation that made use of this feature, the implementation would set up specialised tables in the extra space and the compiler would generate code for instructions or calls to library library support routines that made use of those tables. 在利用此功能的合规实现中,该实现将在额外的空间中建立专用表,并且编译器将为使用这些表的库函数支持例程的指令或调用生成代码。 C++ code using arrays and failing to use new[] would fail on those platforms. 在这些平台上,使用数组且未使用new []的C ++代码将失败。

I am not personally aware of any such implementation, but it resembles the kind of features required for the support of certain mainframes (CDC, IBM, etc) which have an architecture quite unlike the Intel or RISC chips we know and love. 我个人不知道有任何这样的实现,但是它类似于某些大型机(CDC,IBM等)的支持所需的功能,这些大型机的架构与我们熟知和热爱的Intel或RISC芯片完全不同。

In my opinion, the accepted answer is incorrect. 我认为,已接受的答案是错误的。


Just for completeness, the standard (n3936 mostly in S5.3.4) contains the following. 仅出于完整性考虑,该标准(主要在S5.3.4中为n3936)包含以下内容。

  1. A distinction between allocating an 'array object' or a 'non-array object' 分配“数组对象”或“非数组对象”之间的区别
  2. References to 'array allocation overhead', with the implication that extra storage might be needed and it might (somehow) be used for a repetition count or element size. 引用“数组分配开销”,暗示可能需要额外的存储,并且可能(以某种方式)将其用于重复计数或元素大小。

There is no reference to memory pools or any hint that this might be a consideration. 没有引用内存池,也没有任何暗示可能要考虑的提示。

::operator new[] and ~ delete[] facilitate memory usage debugging, being a central point to audit allocation and deallocation operations; ::operator new[]delete[]有助于内存使用调试,这是审核分配和释放操作的中心点; you can then ensure the array form is used for both or neither. 然后,您可以确保将数组形式同时使用或不使用。

There are also lots of plausible if highly unusual/crude tuning uses: 如果非常不寻常/粗暴的调校用途,也有很多合理的理由:

  • allocate arrays from a separate pool, perhaps because that crucially improved average cache hits for small single-object dynamically-allocated objects, 从一个单独的池中分配数组,可能是因为这极大地提高了小型单对象动态分配对象的平均缓存命中率,

  • different memory access hints (ala madvise ) for array/non-array data 数组/非数组数据的不同内存访问提示(ala madvise

All that's a bit weird and outside the day-to-day concerns of 99.999% of programmers, but why prevent it being possible? 所有这些都有些奇怪,超出了99.999%的程序员的日常关注范围,但是为什么要阻止这种可能性呢?

I'm sure there are proper use-cases out there that require separate new[] and new , but I haven't encountered one yet that is uniquely possible with this separation and nothing else. 我敢肯定有适当的用例,需要用到单独的new[]new ,但是我还没有遇到用这种分离唯一可以实现的用例。

However, I see it like this: since the user calls different versions of operator new , the C++ standard would have been guilty of wantonly and deliberately losing information if they'd defined just one operator new and had both new and new[] forward there. 但是,我的看法是这样的:由于用户调用了不同版本的运算符new ,因此,如果C ++标准只定义了一个operator new ,并且其中既有new又有new[]那么它们就会故意肆意丢失信息。 There is (literally) one bit of information here, that might be useful to somebody , and I don't think people on the committee could have thrown it out in good conscience! 这里(字面上)有一点信息, 可能某人有用,而且我认为委员会中的人们不会出于良心抛弃它!

Besides, having to implement the extra new[] is a very very minor inconvenience to the rest of us, if at all, so the trade off of preserving a single bit of information wins against having to implement a single simple function in a small fraction of our programs. 此外,必须实施额外的new[]对我们其他人来说是一个非常小的不便之处,因此,保留一点信息的权衡取舍于必须在一小部分内实现一个简单功能我们的程序。

The C++ Programming Language: Special Edition p 423 says C ++编程语言:特殊版 p 423说

_The operator new() and operator delete() functions allow a user to take over allocation and deallocation of individual objects; _ operator new()operator delete()函数允许用户接管各个对象的分配和释放; operator new[]() and operator delete[]() serve exactly the same role for the allocation and deallocation of arrays. operator new[]()operator delete[]()在数组的分配和释放中的作用完全相同。

Thanks Tony D for correcting my misunderstanding of this nuance. 感谢Tony D纠正了我对此细微差别的误解。

Wow, it's not often I'm caught out on something in C++ I'm so certain about - I must have been spending too much time in Objective-C! 哇,我不太确定会使用C ++上的某些东西-我肯定在Objective-C上花了太多时间!

original wrong answer 原来的错误答案

It's simple - the new[] form invokes the constructor on every element of a classic C array. 很简单-new []表单在经典C数组的每个元素上调用构造函数

So it first allocates the space for all the objects, then iterates calling the constructor for each slot. 因此,它首先为所有对象分配空间,然后迭代为每个插槽调用构造函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM