12

过去,每当我需要创建一个类的实例时,我都会使用 new 在堆上分配它(除了 stl 类,以及像 vec3 和 mat4 这样的数学类)。

然而,我只是在批判性地查看我的一些代码,并意识到从技术上讲,我可以只是在堆栈上创建这些类。它们不是很大,不需要在当前范围之外进行修改等。当我(偶尔)需要将它们传递给另一个函数时,我可以像传递指针一样轻松地使用引用。

过去我总是默认在堆上分配,并且只在某些情况下使用堆栈,但是现在我想知道默认在堆栈上分配是否会更好,并且只在以下情况下使用堆

  • 确实需要一个指针(即对象的生命周期要超过声明的范围)
  • 类或数组对于堆栈来说太大了
  • 继承需要它(抽象基类/接口)
  • 别的东西?

这也提出了一个问题:一个类有多大(大约)太大而无法在堆栈上合理分配?(假设我们至少正在开发智能手机,并升级到高端台式机)我是否只是不必要地担心堆栈大小限制?(可能,只要我们不是在谈论大型数组,并且没有类会接近一千字节)

4

4 回答 4

8

您的默认行为应该是:

如果对象的生命周期与特定范围一致,
即在编译时很容易确定

那么它应该是一个自动存储持续时间对象(类似堆栈)

如果对象的生命周期在运行时定义并超出当前范围

那么它应该是一个动态的存储持续时间对象(类似堆)

注意:所有动态存储持续时间对象都应通过将它们包装在适当的 RAII 类中来控制其生命周期。通常这意味着:对于单个对象一个智能指针,而多个对象最终在一个容器中。

讨厌看到东西被定义为stack Vs heap。因为它没有传达情况的真实语义。

 int x;       // its on the stack
 struct X
 {
     int x;   // Is this a stack or heap object?
 }            // It depends on its parent.


 // But in both cases it is an automatic storage duration object.
 // In both cases the lifespan's are well defined.
 //     The first is defined by the scope it is declared within.
 //     The second is defined by the lifespan of its parent.

您应该考虑自动/动态“存储持续时间”对象。这传达了语言的正确语义。

请注意,还有两种其他类型的变量,因此产生了四种不同类型的变量。自动/动态/静态/线程“存储持续时间”对象。

于 2012-09-08T18:03:21.997 回答
5

我更喜欢在堆栈上分配,原因有两个。首先,在其他条件相同的情况下,它比堆快。此外,释放是自动发生的,我不需要记住delete它(当然,有auto_ptrs 之类的帮助)。

确实需要一个指针

可以将指针传递给堆栈上的对象。只需确保该指针的用户在其生命周期到期后不会访问该对象。

类或数组对于堆栈来说太大了

只有对于真正的大事,这才重要。您可能有 1MB 的堆栈,因此您可以在出现问题之前放置大约 1000 个 1KB 的对象。

继承需要它

为什么会呢?

别的东西?

对象所需的生命周期长于堆栈帧的生命周期。这是在堆上分配的主要原因。

于 2012-09-08T17:52:10.670 回答
1

什么时候应该在堆栈而不是堆上分配一个类?

只要有可能,不会造成很大的不便。会有例外,但作为一般规则回答您的问题:在创建实例时,new/new[]应该输入少于百分之一的时间。


确实需要一个指针(即对象的生命周期要超过声明的范围)

是的,在适当的情况下。从您对 OP 中描述的堆的使用来看,这可能比您想象的要少得多。

类或数组对于堆栈来说太大了

是的,但这应该不是什么大问题——一个很大的类通常表明你的类存在根本性的问题。客户端友好的类可能会考虑在堆上创建那些巨大的、固定大小的数组。

继承需要它(抽象基类/接口)

在某些情况下(例如,存在抽象工厂或多态类型的深层克隆),但随后是工厂创建了类型,并且问题通常在您考虑之前转移到程序对堆栈的使用上。

别的东西?


原因:

  • 它清晰、简洁,并且它的生命周期和范围已经确定。
  • 更少的资源消耗。
  • 更少与内存相关的错误或可能出错的事情。
  • 速度。堆栈分配非常快。更少的锁。
于 2012-09-08T18:36:08.103 回答
-2

只有在需要动态分配内存时才在堆上分配。这意味着您不知道在编译时需要分配多少。您一直在堆栈上分配

于 2012-09-08T17:48:58.587 回答