对象列表应该存储在堆还是栈上?

Posted

技术标签:

【中文标题】对象列表应该存储在堆还是栈上?【英文标题】:Should a list of objects be stored on the heap or stack? 【发布时间】:2010-10-13 10:09:37 【问题描述】:

我有一个对象(A),它有一个由对象(B)组成的列表。 list(B) 中的对象是指针,但列表本身应该是指针吗?我正在从 Java 迁移到 C++,但还没有完全习惯堆栈/堆。该列表不会传递到 A 类之外,只会传递列表中的元素。为了以防万一,将列表本身分配在堆上是一种好习惯吗?

另外,包含 list(A) 的类也应该在堆上吗?和列表一样,不会被传递。

【问题讨论】:

【参考方案1】:

请记住

    只有当 Object-A 也在堆栈中时,列表才会在堆栈中 即使列表本身不在堆上,它也可以从堆中分配其存储空间。这就是 std::list、std::vector 和大多数 C++ 列表的工作方式——原因是基于堆栈的元素不能增长。 如今,大多数堆栈都在 1mb 左右,因此您需要一个相当大的对象列表才能担心它。即使您的堆栈只有大约 32kb,您也可以存储近 8000 个指针,以免成为问题。

不熟悉 C/C++ 中显式内存管理的 IMO 人员可能倾向于过度思考这些事情。

除非您正在编写一些您知道会有数千个相当大的对象的东西,否则只需将列表放入堆栈中。除非您在函数中使用巨大的 C 样式数组,否则由于上面的 #1 和 #2,列表使用的内存可能最终会在堆中。

【讨论】:

"原因是基于栈的元素不能增长。"我相信你可以增长一个基于堆栈的元素,但你必须重新分配它们。【参考方案2】:

“列表”是什么意思。如果它是 std::list (或 std::vector 或任何其他 STL 容器),那么它不会在堆栈上存储任何东西,所以不用担心。

如果您有任何疑问,请查看 sizeof(A),它会告诉您它在堆栈上时将使用多少内存。

但是...决定应该主要基于对象的生命周期。基于堆栈的对象一旦超出范围就会被销毁。

【讨论】:

【参考方案3】:

我在堆栈可能很小并且需要避免堆碎片的环境中工作,所以我会使用这些规则:

如果列表很小且已知固定大小,则堆栈。

如果列表很小且固定大小未知,则可以同时考虑堆和 alloca()。如果您可以保证您的函数在您的分配将在那里的持续时间内不会在堆上分配任何东西,那么使用堆将是一个不错的选择。如果你不能保证这一点,你要求一个片段,alloca() 会是一个更好的选择。

如果列表很大或需要增长,请使用堆。如果你不能保证它不会碎片化,我们倾向于在内存管理器中内置一些资源,例如自上而下的分配和单独的堆。

大多数情况下不需要人们担心碎片,在这种情况下,他们可能不推荐使用 alloca。

对于包含列表的类,如果它在函数范围内是本地的,只要内部数据结构不是非常大,我会将它放在堆栈上。

【讨论】:

【参考方案4】:

如果列表可以增长,最好将其存储在堆上。由于您永远不知道运行时堆栈将是什么,因此溢出是一种真正的危险,其后果是致命的。

如果您绝对知道列表的上限,并且与堆栈的大小相比它很小,那么您可能可以避免堆栈分配列表。

【讨论】:

如果列表存储的是指向堆的指针,难道不是需要大量元素导致堆栈溢出吗?对于这个应用程序,如果列表包含 30 多个元素,那就太疯狂了。 如果它是“std::list”中的列表,那么它不会在堆上存储任何东西。 Bor 是任何其他 STL 容器。【参考方案5】:

堆栈总是最简单的。不幸的是,它有一个很大的缺点——你必须提前知道元素的数量。

【讨论】:

以上是关于对象列表应该存储在堆还是栈上?的主要内容,如果未能解决你的问题,请参考以下文章

字符串类型是存储在堆上还是栈上?

C++中,静态数组在内存中是存储在堆上,还是栈上,还是在静态存储区中?

对象的私有成员是在堆上还是在栈上?

基本类型声明在堆上还是栈上

只能在堆上或栈上创建对象的类

Go 语言中的变量究竟是分配在栈上还是分配在堆上?