A* pca = new A[3];  // 调用3次 default ctor (即没有参数的构造函数)
// 在 array new 的时候, malloc 会在 对应3个 A 的头处,添加cookie,用于记录 array 的长度
// 以便在 free 的时候可以知道具体需要 free 多少个元素

// 调用其他构造函数
A* tmp = pca;
for (int i = 0; i < 3; ++i) new (tmp++) A(i);  // 定点new: 使用tmp的内存来执行其他构造函数

delete[] pca;  // 同样需要调用3次 dtor, 依次从后往前析构
//! delete pca;  // 如果这么写,会导致只析构一个元素,从而造成其他两个A的内存泄漏(具体释放哪一个不同编译器有不同实现),但A本身是会被释放掉的
// 也就是说,如果 A 是 class with pointer member, 则会造成内存泄漏

array 内存模型

通过 array new 得到的内存模型如下所示

在32位电脑上,使用 array new 获得的指针指向的是上图的 00441c30, 但实际在底层 malloc 还会额外分配内存,如上图的 绿色、黄色还有蓝色部分,这一部分内存称之为额外开销。

如果打开了 debug mode,则固定会有黄色部分,一共 32 + 4 = 36 字节

绿色部分称之为 Cookie, 一共是 4 * 2 = 8 bytes

则对于上图左侧的内存,其内存一共是 4 * 2 + 7 * 4 + 32 + 4 = 72, 而后为了满足内存分页,还需要补齐一段内存(即上图 Pad 部分),以达到 16 的倍数(该标准由编译器与系统决定),故 80 - 72 = 8,补上8bytes,并且在 cookie 上记录这块内存的大小,即 0x50 = 50h。同时CPP借用最后一位(16 倍数最后4为一定为 0)用于记录该块内存是否使用,故最终记录为 51h。

而对于上图右侧,对于 Class,在分配的时候,会记录长度,以便可以正确的调用析构函数。长度同样也占4bytes。