在 C 和 C++ 中如何分配和释放 *array* 内存?

Posted

技术标签:

【中文标题】在 C 和 C++ 中如何分配和释放 *array* 内存?【英文标题】:How is *array* memory allocated and freed in C and C++? 【发布时间】:2009-08-20 08:23:35 【问题描述】:

我的问题是关于数组,不是对象。

关于malloc()/free()new/delete 的 SO 存在一些问题,但所有问题都集中在它们的使用方式上的差异。我了解它们的使用方式,但我不了解导致使用差异的根本差异。

我经常听到 C 程序员malloc()free() 是昂贵的操作,但我从未听过 C++ 程序员这样说 newdelete。我还注意到 C++ 没有对应于 C 的realloc() 的操作。

如果我正在编写与 C++ 的 vector 类等效的类,我希望在调整其大小时避免复制整个数组,但使用 newdelete 你必须复制。在 C 语言中,我会简单地 realloc()。值得注意的是,realloc() 可能只是复制整个数组,但我的印象是它使用相同的指针并为其分配的空间更少,至少在缩小尺寸时是这样。

所以我的问题是,malloc()free() 使用的算法与 newdelete 使用的算法有何不同。更具体地说,为什么 C 方式有更昂贵的污名,为什么 C++ 方式不允许在不复制的情况下调整大小?

【问题讨论】:

realloc 非常时髦,它会根据实际参数和当前内存使用情况分配、删除、就地重新分配或重新分配和移动(从而使其他指针无效)。 IE。你不能从代码中真正看出它会做什么。 【参考方案1】:

在底层并没有真正的区别 - 通常默认的 newdelete 运算符将简单地调用 mallocfree

至于“更贵的耻辱”,我的理论是这样的:在过去,每个周期都很重要,malloc 所花费的时间在许多情况下确实很重要。但是当 C++ 出现时,硬件速度要快得多,免费商店经理所花费的时间也相应地减少了。重点从高效利用机器资源转向高效利用程序员资源。

我不知道为什么 C++ 缺少 realloc 等效项。

【讨论】:

因为 realloc 很多时候只是简单地分配一个新块,将旧数据复制到新块,然后释放原始块。如果您想要一个动态调整大小的数组,请使用 std::vector 回到过去?好吧,看看 malloc 的代码,你就会明白为什么即使在今天它也会很昂贵。为什么你认为有这么多关于高效垃圾收集的研究?如果有的话,今天更糟,因为代码中有太多的 alloc/free,而没有太多考虑成本。 @xcramps:我的意思是,这是一个认知问题,而不是有形的技术差异。 是的,即使在今天,频繁的重新分配也会使应用程序变得更慢。这就是为什么有vector::reserve()。 @Goz:是的,但必须有人用 C++编写std::vector。为什么该人被拒绝 realloc 等效项?【参考方案2】:

new 和 delete 通常使用 malloc() 和 free() 进行内存分配/释放。无论如何,他们必须使用一些原语进行内存分配/释放 - 重载 newdelete 运算符,这可能比 malloc() 和 free() 更快(比如说它可以在固定大小对象的内存池上工作的函数)。通常,除非您实际上已经完成了此类重载,否则您不会看到每种方式的内存分配成本有任何差异。

不允许重新分配,因为并非所有数据类型都允许在内存中移动——它们需要调用复制构造函数和析构函数才能正确移动。例如,您可能将一些图形节点结构存储在数组中。如果你盲目地移动它们,指向对象之间的指针将失效。

【讨论】:

【参考方案3】:

“新建和删除可能是昂贵的操作” - 在那里,你现在有了 听一个 C++ 程序员这么说。但严重的是,两种语言的动态内存分配成本相同。

【讨论】:

好吧,实际上它“可以”花费更多来做一个新的,因为每个项目都会调用构造函数...... @Goz。原始类型的构造函数什么都不做,任何体面的编译器都会很乐意优化它们。【参考方案4】:

我不知道 C 的“耻辱”,但用于调整 C++ 的大小。您可以使用placement new 来自定义new 的行为。

但是为什么要这样做呢?让编译器制造者做他们最擅长的事情!

【讨论】:

您是否有任何链接可以说明如何进行此操作?【参考方案5】:

概括地说,C 传统上被用于资源受限的环境中,这既是因为它的存在时间更长,而且因为它用于嵌入式应用程序。因此,malloc 的潜在计算成本令人担忧,而在 PC 上更常用的 C++ 则不那么担心。

newdelete 很可能由您的编译器以与 malloc 非常相似的方式实现,但它们有一个区别(这就是它们存在的原因)——它们调用相关项的构造函数和析构函数。

当我说构造函数时,我当然是指所需的任何初始化(填写 VTABLES、设置初始化程序等)。这可能会使newdelete 变慢,但在并排比较中(例如分配和释放int)没有根本区别。

【讨论】:

【参考方案6】:

它们从根本上使用相同的分配技术——当然,在大多数实现中,默认的 C++ 运行时 new 不会比 malloc 快多少。最大的区别之一是您可以在 C++ 中重写分配器,这样您就可以使用针对您预期的内存行为优化的分配器 - 当然,您也可以在 C 中这样做,但是在语法方面有点麻烦。

【讨论】:

以上是关于在 C 和 C++ 中如何分配和释放 *array* 内存?的主要内容,如果未能解决你的问题,请参考以下文章

C++二维数组内存分配

c++中new和delete的用法

如何在 C++ 中动态分配数组

共享内存实现上的 C++ 内存池:这种分配和释放方法是不是正确?

C++对象的动态建立与释放

小白学习C++ 教程十六C++ 中的动态内存分配