使用堆或堆栈变量更好吗?

时间:2012-06-02 06:21:24

标签: c++ variables stack heap

我前段时间和朋友讨论过。他是一位经验丰富的C ++用户,我不是一位经验丰富的C ++用户。他告诉我,我应该努力使用堆变量,即:

A* obj = new A("A");

而不是:

A obj("A");

除了使用指针好又灵活的所有东西之外,他说把东西放在堆而不是堆栈中更好(堆栈的东西比堆小?)。这是真的吗?如果是这样的话?

编辑:我说我的朋友建议堆栈变量我写了一个错字。他在推荐堆变量。

Edit2:我知道有关生命的问题。让我们假设我已经适当地管理了这些变量的生命周期。 (即关注的唯一标准是堆与堆栈存储,没有终身问题)

8 个答案:

答案 0 :(得分:12)

根据上下文,我们需要使用堆或堆栈。每个线程都获得一个堆栈,线程通过调用函数来执行指令。调用函数时,函数变量将被推送到堆栈。当函数返回堆栈回滚并回收内存时。现在线程局部堆栈有一个大小限制,它有所不同,可以在某种程度上进行调整。如果在堆栈上创建每个对象并且对象需要大内存,则考虑到此限制,则堆栈可能会耗尽,从而导致堆栈溢出错误。除此之外,如果要通过多个线程访问对象,那么将这样的对象存储在堆栈上是没有意义的。

因此,应将小变量,小对象和指针存储在堆栈中。将对象存储在堆或免费存储上的问题是,内存管理变得困难。内存泄漏的可能性很大,这很糟糕。此外,如果应用程序尝试访问已删除的对象,则可能会发生访问冲突,从而导致应用程序崩溃。

C ++ 11引入了智能指针(共享,唯一),使堆内存管理更容易。实际引用的对象在堆上,但是由智能指针封装,该指针始终在堆栈上。因此,当函数返回事件期间或异常期间堆栈回滚时,智能指针的析构函数会删除堆上的实际对象。在共享指针的情况下,保持引用计数,并且当引用计数为零时删除实际对象。 http://en.wikipedia.org/wiki/Smart_pointer

答案 1 :(得分:7)

堆栈应该优先于堆,因为堆栈分配的变量是自动变量:当程序退出上下文时,它们的销毁会自动完成。

实际上,在堆栈和堆上创建的对象的生命周期是不同的:

  • 函数或代码块{}的局部变量(未由new分配)在堆栈上 。从函数返回时,它们自动销毁。 (他们的析构函数被调用,他们的记忆被释放)。
  • 但是,如果你需要在函数之外使用某个对象,你必须在堆上分配(使用new)或返回副本。

示例:

 void myFun()
 {
   A onStack; // On the stack
   A* onHeap = new A(); // On the heap
   // Do things...

 } // End of the function onStack is destroyed, but the &onHeap is still alive

在此示例中,onHeap在函数结束时仍将分配其内存。这样,如果某个地方没有指向onHeap的指针,您将无法删除它并释放内存。这是一个内存泄漏,因为在程序结束之前内存将会丢失。

但是如果要在onStack上返回一个指针,因为退出函数时onStack被销毁,使用指针可能会导致未定义的行为。使用onHeap仍然完全有效。

为了更好地了解堆栈变量的工作原理,您应该搜索有关调用堆栈的信息,例如this article on Wikipedia。它解释了如何堆叠变量以在函数中使用。

答案 2 :(得分:4)

最好避免在C ++中尽可能多地使用 new 但是,有时候你无法避免它 例如:
希望变量存在于其范围之外。

所以它应该是真正的课程,但如果你有选择总是避免堆分配变量。

答案 3 :(得分:4)

关于堆栈分配与堆分配变量的使用,没有一般规则。根据您的目的,只有指南。

以下是一些优点和缺点:

堆分配:

优点:

  • 更灵活 - 如果您有大量在编译时无法获得的信息
  • 更大 - 你可以分配更多 - 但是,它不是无限的,所以在某些时候,如果分配/解除分配没有得到正确处理,你的程序可能会耗尽内存

缺点:

  • 慢 - 动态分配通常比堆栈分配慢
  • 可能导致内存碎片 - 分配和释放不同大小的对象将使内存看起来像瑞士奶酪:)如果没有所需大小的内存块,导致某些分配失败
  • 难以维护 - 正如您所知,每个动态分配必须后跟一个应该由用户完成的解除分配 - 这很容易出错,因为在很多情况下人们忘记匹配每个malloc()调用free()调用或new()with delete()

堆栈分配:

优点:

  • 更快 - 这对于嵌入式系统来说非常重要(我相信对于嵌入式系统,有一条禁止动态分配的MISRA规则)
  • 不会导致内存碎片
  • 使应用程序的行为更具确定性 - 例如消除某些时候内存不足的可能性
  • 不易出错 - 因为用户不需要处理解除分配

缺点:

  • 不太灵活 - 您必须在编译时获得所有信息(数据大小,数据结构等)
  • 尺寸较小 - 但是有办法计算应用程序的总堆栈大小,因此可以避免堆栈耗尽

我认为这抓住了一些利弊。我相信还有更多。

最终取决于您的应用需求。

答案 4 :(得分:1)

答案并不像有些人会让你相信那样明确。

通常,您应该更喜欢自动变量(在堆栈上),因为它更容易。但是有些情况需要动态分配(在堆上):

  • 编译时未知大小
  • 可扩展(容器在内部使用堆分配)
  • 大型物件

后者有点棘手。从理论上讲,自动变量可以无限分配,但计算机是有限的,更糟糕​​的是,大多数情况下堆栈的大小也是有限的(这是一个实现问题)。

就个人而言,我使用以下指南:

  • 自动分配本地对象
  • 本地数组被推迟到std::vector<T>,在内部动态分配它们

它对我很有帮助(显然这只是轶事证据)。

注意:您可以(并且可能应该)使用RAII将动态分配的对象的生命周期与堆栈变量的生命周期联系起来:智能指针或容器。

答案 5 :(得分:0)

C ++没有提到堆或堆栈。就语言而言,它们不存在/不是分开的东西。

至于实际答案 - 使用最有效的方法 - 你需要快速 - 你需要保证吗?对于堆上的所有内容,应用程序A可能会好得多,应用程序B可能会破坏操作系统内存,因此它会杀死机器 - 没有正确的答案: - (

答案 6 :(得分:0)

简单地说,除非你需要,否则不要管理你自己的记忆。 ;)

答案 7 :(得分:-4)

Stack =在编译期间分配的静态数据。 (不是动态的)

堆=运行时分配的动态数据。 (非常有活力)

尽管指针位于堆栈上......这些指针很漂亮,因为它们为动态,自发的数据创建打开了大门(取决于您对程序进行编码的方式)。

(但我只是一个野蛮人,所以为什么我说的很重要)