Foo* set = new Foo[100];
// ...
delete [] set;
在使用delete[]
删除数组时,不要超出数组的边界。但是这些信息存储在哪里?是否有标准化?
Foo* set = new Foo[100];
// ...
delete [] set;
在使用delete[]
删除数组时,不要超出数组的边界。但是这些信息存储在哪里?是否有标准化?
当你在堆上分配内存时,你的内存分配器会跟踪你已经分配了多少内存。这通常存储在一个“head”段中,就在你被分配的内存之前。因此,当释放内存的时候,解除分配器知道需要释放多少内存。
free
如何知道要释放多少内存”。是的,内存块大小通常由malloc
(通常在块本身中)存储在“某个地方”,因此这就是free
如何知道的。然而,new[]
/delete[]
则是另一回事。后者基本上是在malloc
/free
之上运作的。 new[]
还将其创建的元素数存储在内存块中(独立于malloc
),以便稍后的delete[]
可以检索并使用该数字来调用适当数量的析构函数。 - AnT stands with Russiamalloc
)和元素计数(通过new[]
)。需要注意的是,前者不能用于计算后者,因为在一般情况下,内存块的大小可能比所请求的数组所需的更大。还要注意,仅针对具有非平凡析构函数的类型才需要数组元素计数器。对于具有平凡析构函数的类型,计数器不会由new[]
存储,并且当然不会由delete[]
检索。 - AnT stands with Russia编译器之一的方法是分配更多的内存,并在头元素中存储元素数量。
以下是一个示例:
这里
int* i = new int[4];
编译器将会分配 sizeof(int)*5
字节。
int *temp = malloc(sizeof(int)*5)
将“4”存储在第一个sizeof(int)
个字节中
*temp = 4;
并设置i
i = temp + 1;
所以i
将指向一个由4个元素组成的数组,而不是5个。
删除
delete[] i;
将按照以下方式进行处理:
int *temp = i - 1;
int numbers_of_element = *temp; // = 4
... call destructor for numbers_of_element elements
... that are stored in temp + 1, temp + 2, ... temp + 4 if needed
free (temp)
ptr[-1]
。 - user4945014这些信息并没有标准化。然而,在我所工作的平台上,这些信息存储在第一个元素之前的内存中。因此理论上你可以访问并检查它,但这并不值得。
同时也正因为如此,当你使用new[]分配内存时,必须使用delete[]来释放内存,因为数组版本的delete知道(和在哪里)需要查找以释放正确数量的内存 - 并调用适当数量的对象析构函数。
这是由C++标准定义的,因此是特定于编译器的。这意味着它具有编译器魔法的性质。在至少一个主要平台上,它可能会受到非平凡对齐限制的影响而出现问题。
您可以通过意识到delete[]
仅针对由new[]
返回的指针定义,该指针可能与operator new[]
返回的指针不同来思考可能的实现。一种实现方式是将数组计数存储在由operator new[]
返回的第一个int中,并使new[]
返回超过该计数的指针偏移量。(这就是为什么非平凡对齐可能会破坏new[]
的原因。)
请记住,operator new[]/operator delete[]
!=new[]/delete[]
。
此外,这与C如何知道malloc
分配的内存大小无关。
[信息][您请求的内存...]
其中,信息是编译器用于存储所分配内存数量等信息的结构体。
不过这取决于实现方式。
这不是规范中的内容,而是依赖于具体的实现。
因为要“删除”的数组应该是使用“new”运算符创建的。这个“new”操作应该将信息放在堆上。否则,其他使用new的操作怎么知道堆在哪里结束呢?
这个问题比你一开始想象的更有趣。这篇回复是关于可能的实现方式。
首先,在某个层面上,你的系统必须知道如何“释放”内存块,但底层的malloc/free(通常由new/delete/new[]/delete[]调用)并不总是记得准确地请求了多少内存,它可以被舍入(例如,一旦超过4K,它经常被舍入到下一个大小为4K的块)。
因此,即使能够获得内存块的大小,也不能告诉我们新分配的内存中有多少值,因为它可能更小。因此,我们必须存储一个额外的整数来告诉我们有多少个值。
除非正在构造的类型没有析构函数,否则delete[]除了释放内存块之外什么也不需要做,因此不需要存储任何东西!
这并不是标准化的。在微软的运行时中,new操作符使用malloc()函数,而delete操作符使用free()函数。因此,在这种情况下,你的问题等同于以下问题:free()如何知道块的大小?
背后有一些书记工作,即在C运行时中进行。