Foo* set = new Foo[100]; // ... delete [] set;
你不会把数组的边界传递给 delete[]。但是这些信息存储在哪里呢? 它是标准化的吗?
delete[]
这不是规范中的内容——它取决于实现。
因为要“删除”的数组应该是用“new”操作符创建的。'new'操作应该已经将该信息放到堆上。否则,new的其他用法如何知道堆的结束位置?
当你在堆上分配内存时,你的分配器会跟踪你已经分配了多少内存。它通常存储在分配内存之前的“head”段中。这样,当需要释放内存时,解分配器确切地知道需要释放多少内存。
它不是标准化的。在微软的运行时,new操作符使用malloc(), delete操作符使用free()。因此,在此设置中,您的问题相当于以下内容:free()如何知道块的大小?
在幕后,也就是在C运行时,会进行一些簿记工作。
信息没有标准化。然而,在我所研究的平台中,这些信息存储在内存中,就在第一个元素之前。因此,理论上你可以访问它并检查它,但这并不值得。
这也是为什么在使用new[]分配内存时必须使用delete[]的原因,因为数组版本的delete知道(以及在哪里)它需要寻找释放适当数量的内存-并为对象调用适当数量的析构函数。
它在c++标准中定义为特定于编译器的。这意味着编译器的魔力。它可以打破至少一个主要平台上的重要对齐限制。
你可以通过意识到delete[]仅为new[]返回的指针定义,而new[]返回的指针可能与operator new[]返回的指针不同来考虑可能的实现。野外的一个实现是将数组计数存储在operator new[]返回的第一个int中,并让new[]返回一个指针偏移量超过该值。(这就是为什么非平凡对齐会破坏new[]。)
new[]
operator new[]
记住operator new[]/operator delete[]!=new[]/delete[]。
operator new[]/operator delete[]
new[]/delete[]
另外,这与C如何知道malloc分配的内存大小是正交的。
malloc
基本上它在内存中的排列方式是:
[信息][mem你要的是…]
这里的info是编译器用来存储分配的内存量的结构。
不过,这取决于实现。
编译器的一种方法是多分配一点内存,并在头元素中存储元素的计数。
举例说明:
在这里
int* i = new int[4];
编译器将分配sizeof(int)*5字节。
sizeof(int)*5
int *temp = malloc(sizeof(int)*5)
将“4”存储在第一个sizeof(int)字节
sizeof(int)
*temp = 4;
并设置i
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)
这是一个比你最初想象的更有趣的问题。这个回复是关于一个可能的实现。
首先,在某种程度上,你的系统必须知道如何“释放”内存块,底层的malloc/free (new/delete/new[]/delete[]通常调用)并不总是准确地记住你需要多少内存,它可以四舍五入(例如,一旦你超过4K,它通常四舍五入到下一个4K大小的块)。
因此,即使可以得到内存块的大小,也不能告诉我们在新的[]ed内存中有多少值,因为它可以更小。因此,我们必须存储一个额外的整数来告诉我们有多少个值。
除非,如果被构造的类型没有析构函数,那么delete[]除了释放内存块外什么都不用做,因此不需要存储任何东西!