19

使用 分配数组时new [],为什么不能从指针中找出该数组的大小?它必须在运行时知道,否则delete []不知道要释放多少内存。

除非我错过了什么?

4

4 回答 4

15

在典型的实现中,动态内存块的大小以某种方式存储在块本身中 - 这是真的。但是没有标准的方式来访问这些信息。(实现可以提供特定于实现的方式来访问它)。这就是它的样子malloc/free,这就是它的样子new[]/delete[]

事实上,在一个典型的实现中,new[]/delete[]调用的原始内存分配最终由一些特定于实现的malloc/free类对处理,这意味着它delete[]并不需要真正关心要释放多少内存:它只是调用内部的free(或任何它被命名),它会处理这个问题。

但是,需要知道的是在数组元素类型具有非平凡析构函数的情况下要销毁delete[]多少元素。这就是你的问题 -数组元素的数量,而不是块的大小(这两个不一样,块可能比数组本身实际需要的大)。出于这个原因,数组中的元素数量通常也存储在块内,然后由检索,以执行正确的数组元素销毁。也没有访问此号码的标准方法。new[]delete[]

(这意味着在一般情况下,分配的典型内存块new[]将独立地同时存储物理块大小(以字节为单位)数组元素计数。这些值由不同级别的 C++ 内存分配机制存储 - 原始内存分配器及其new[]本身分别 - 并且不以任何方式相互交互)。

但是,请注意,由于上述原因,数组元素计数通常仅在数组元素类型具有非平凡析构函数时存储。即这个计数并不总是存在。这就是为什么提供标准方法来访问该数据不可行的原因之一:您要么必须始终存储它(这会浪费内存),要么通过析构函数类型限制它的可用性(这令人困惑)。

为了说明上述情况,当您创建一个ints数组时

int *array = new int[100];

数组的大小(即100)通常存储,new[]因为delete[]不关心它(int没有析构函数)。块的物理大小(如 400 字节或更多)通常由原始内存分配器存储在块中(并由 调用的原始内存释放器使用delete[]),但对于某些实现,它很容易变成 420 ——具体原因。所以,这个大小对你来说基本上是无用的,因为你不能从中得出确切的原始数组大小。

于 2010-03-09T00:20:40.720 回答
7

您很可能可以访问它,但它需要对您的分配器有深入的了解并且不可移植。C++ 标准没有指定实现如何存储这些数据,因此没有一致的方法来获取它。我相信它没有被指定,因为不同的分配器可能希望以不同的方式存储它以提高效率。

于 2010-03-09T00:09:29.867 回答
5

这是有道理的,例如,分配的块的大小可能不一定与数组的大小相同。虽然确实可以new[]存储元素的数量(调用每个元素的析构函数),但它不是必须的,因为空析构函数不需要它。也没有标准方法(C++ FAQ Lite 1C++ FAQ Lite 2)来实现new[]存储数组长度的位置,因为每种方法都有其优点和缺点。

换句话说,它通过不指定任何有关实现的内容来允许尽可能快且便宜的分配。(如果实现必须每次都存储数组的大小以及分配的块的大小,则会浪费您可能不需要的内存)。

于 2010-03-09T00:10:39.170 回答
3

简单地说,C++ 标准不需要对此提供支持。如果您对编译器的内部有足够的了解,您可能会弄清楚如何访问这些信息,但这通常被认为是不好的做法。请注意,堆分配数组和堆栈分配数组的内存布局可能有所不同。

请记住,本质上你在这里谈论的也是 C 风格的数组——尽管newdelete是 C++ 运算符——并且行为是从 C 继承的。如果你想要一个大小合适的 C++“数组”,你应该使用STL(例如 std::vector、std::deque)。

于 2010-03-09T00:18:11.897 回答