【问题标题】:Why does operator new[] allocate memory for the size of the array?为什么 operator new[] 为数组的大小分配内存?
【发布时间】:2018-10-08 16:53:39
【问题描述】:

我正在实现一个堆栈分配器,并为某个类重载了operator new[] 以使用我自己的分配器。然后我注意到operator new[] 为分配的数组中的元素数量分配了内存。
比如:

test_class* test_arr = new test_class[5];

从我的分配器请求 8 个字节 + 5*sizeof(test_class) 并在前 8 个字节中存储数组的大小,在本例中为 5。

为什么要这样做?我的分配器的工作是跟踪分配的内存量。对于那部分,它真的没有意义,不是吗?那么有什么意义呢? 另外,我可以(或不应该?)以某种方式“关闭它”吗?

【问题讨论】:

  • 分配器通过存储大小和分配的内存来跟踪分配的内存。查看operator delete[] 的代码。
  • @MustafaOzturk 在 libstdc++ 中 delete 仅将 void* 传递给 std::free。因此,在我的示例中,它将传递一个指向第一个 test_class 元素的指针。 free 对指针的类型一无所知,那么为什么数组中的元素数量会带来好处呢?
  • 我不是专家,但我认为如果你的类有一个重要的析构函数,delete[] 需要知道要调用多少个元素
  • delete[] 不是delete。要在 C++ 中释放数组,您需要使用 delete[]。因此,要正确删除上述分配,您必须调用 delete[](test_arr)
  • operator new[] 存储数组中的对象数量,以便operator delete[] 知道必须销毁多少对象。

标签: c++ dynamic-memory-allocation


【解决方案1】:

new T[N] 很可能会请求一个指向 sizeof(size_t) + N * sizeof(T) 字节大小的内存的指针 p,将 N 存储在第一个 sizeof(size_t) 字节中,然后将 (T*)(((size_t*)p)+1) 返回给用户(所以第一个 T 是位于返回的指针处。)

然后delete[] 将获取给定的指针,查看*(p-sizeof(size_t)) 看看要销毁多少对象,销毁它们,然后将((size_t*)p)-1 传递给底层分配器以释放。

【讨论】:

  • 似乎是这样,但标准规定了吗?还有一个void* 传递给delete[],delete 怎么知道要调用哪个类的析构函数?
  • @MikevanDyke:析构函数在传递给delete[]时已经被调用。
  • 小心假指针算法:*(p-sizeof(size_t)) 没有意义,除非p 具有char* 类型。对于任何其他指针类型p-sizeof(size_t) 指向杂草,并且行为未定义。
  • 你可以改用(size_t *)p-1
  • @jxh——也许吧。我的意思更多的是建议谈论它是如何工作的,而不是试图拼凑一个可能显示或不显示实际情况的代码 sn-p。
【解决方案2】:

当您在代码中编写p = new T[N] 时,编译器会生成调用operator new[] 的代码,以便为T 类型的N 对象以及它需要的任何簿记信息分配足够的内存。当您随后调用delete[] p 时,编译器为p 指向的数组中的每个N 元素调用析构函数,然后调用operator delete[] 以释放它从operator new[] 获得的内存。

N 并不总是具有相同的值。您可以使用p = new T[3]; delete[] p; p = new T[4]; delete[] p;,这两个删除操作将分别运行不同数量的析构函数。

为了调用正确数量的析构函数,必须在某处记录p 指向的数组中有多少对象。该注释通常存储在编译器从调用operator new[] 获得的内存的簿记部分中。这就是它需要额外空间的原因。

这是当今的典型实现,但编译器不需要这样做。例如,至少有一个早期的实现保留了一个单独的指针值和析构函数计数表。

此外,许多实现不使用没有析构函数的类型的额外开销。所以int *p = new int[3] 会简单地调用operator new(3*sizeof(int),而delete[] p 会简单地调用operator delete(p)

【讨论】:

    猜你喜欢
    • 2017-01-31
    • 2017-03-29
    • 1970-01-01
    • 2014-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-26
    • 1970-01-01
    相关资源
    最近更新 更多