Answers:
在堆上分配内存时,分配器将跟踪已分配的内存量。这通常存储在分配内存之前的“ head”段中。这样,当需要释放内存时,解除分配器就会确切知道要释放多少内存。
free
知道要释放多少内存”。是的,内存块大小是“某处”存储的malloc
(通常存储在该块本身中),因此可以free
知道。但是,new[]
/ delete[]
是一个不同的故事。后者基本上在malloc
/ 之上工作free
。new[]
还将创建的元素数量存储在内存块中(与无关malloc
),以便以后delete[]
可以检索并使用该数量来调用适当数量的析构函数。
malloc
)和元素计数(按new[]
)。注意,前者不能用于计算后者,因为在一般情况下,存储块的大小可能大于请求的大小数组的实际所需大小。还要注意,只有具有非平凡析构函数的类型才需要使用数组元素计数器。对于具有琐碎析构函数的类型,计数器不会由存储new[]
,当然也不会由检索delete[]
。
编译器的一种方法是分配更多的内存,并将一定数量的元素存储在head元素中。
示例如何完成:
这里
int* i = new int[4];
编译器将分配sizeof(int)*5
字节。
int *temp = malloc(sizeof(int)*5)
将在前sizeof(int)
几个字节中存储“ 4”
*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)
它在C ++标准中定义为特定于编译器。这意味着编译器魔术。在至少一个主要平台上,它可能会因非平凡的对齐限制而中断。
您可以通过意识到delete[]
仅为返回的指针定义的实现来考虑可能的实现,该指针new[]
可能与返回的指针不同operator new[]
。常见的一种实现方式是将数组计数存储在由返回的第一个int中operator new[]
,并new[]
返回超出该值的指针偏移量。(这就是为什么非平凡的对齐方式可能会中断的原因new[]
。)
请记住operator new[]/operator delete[]
!= new[]/delete[]
。
另外,这与C如何知道由分配的内存大小正交malloc
。
这是一个比您一开始可能想到的有趣的问题。此答复是关于一种可能的实现。
首先,虽然您的系统必须在某种程度上知道如何“释放”内存块,但底层的malloc / free(通常会调用new / delete / new [] / delete [])并不总是记住确切的内存量您要求将其四舍五入(例如,一旦高于4K,通常会将其四舍五入到下一个4K大小的块)。
因此,即使可以获得内存块的大小,也不会告诉我们new [] ed内存中有多少个值,因为它可以更小。因此,我们必须存储一个额外的整数,告诉我们有多少个值。
除此以外,如果正在构造的类型没有析构函数,那么delete []除了释放内存块外无需执行任何操作,因此也不需要存储任何内容!