C++对象块分配与单独分配

4
块分配和单个对象分配有什么主要区别?例如:
int iCount = 5;

int i = 0;
while(i < iCount)
{
  f = new foo();
 i++;
}

//////////////////
foo* f = new foo[iCount];

第二种方法会节省我一些内存空间吗?. 我听说我们分配的每个对象都被16个管理字节所包围。因此,块分配将只使用一个头部保护。这是真的吗?。


我听说我们分配的每个对象都被16个管理字节所包围。因此,块分配只会使用一个头保护。这是真的吗? - nsa
我没有听说过那个谣言。另一方面,new[] 可能需要在某个地方存储 iCount,以便 delete[] 可以找到它。也许这会使用更多的内存,而不是更少? - Bo Persson
2个回答

3
每次分配都会分配一个分配头(有时还有一些页脚保护结构),这取决于您的分配器使用的算法。在这里,您可以找到其中一种算法的描述。
当您分配数组时,分配器(主要是malloc())将使用sizeof(element)*count作为参数调用,并将整个数组作为一个块进行分配,使用一个头结构体,因此它将引入比逐个分配元素更少的内存开销(请参见底部的注释)。
无论如何(由于问题标记为),好的C++程序员应避免手动管理内存。对于数组,请使用标准库类(vectormaplist等)。尽可能使用RAII,不要使用裸指针,而是使用“智能”指针。
注意:我在这里写的一切都完全取决于所使用的算法,因此关于数组分配的段落可能不适用于所有可能的内存分配算法。因此,“块分配与单个对象分配之间的主要区别是什么”直接回答也取决于算法。


1

另一个非常重要的区别是异常安全性。在您的代码中:

int iCount = 5;
int i = 0;
while(i < iCount)
{
    f = new foo();
    i++;
}

在编写代码时,一定要非常小心,以避免出现内存泄漏;你必须记住所有的foo,以便在发生异常时能够正确清理。如果这段代码在构造函数中,仅在析构函数中释放内存是不够的,因为如果抛出异常,对象就无法被创建,析构函数也不会被调用。这进一步导致编写正确的复制构造和复制赋值,每个都要安全处理异常等。

教训:使用标准容器,如vectorlistdeque(还有更多)。

//////////////////
foo* f = new foo[iCount];

如果在分配第一个和最后一个foo之间抛出异常,这将至少销毁每个构造的foo

当然,您必须确保f将被正确删除,特别是如果有其他抛出点执行此分配的代码。

道德:使用标准容器。手动内存管理可能在第一眼看起来微不足道,特别是如果您来自C语言,但编写异常安全代码是非微不足道且至关重要的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接