C++ 什么时候应该在堆栈而不是堆上分配类

C++ 什么时候应该在堆栈而不是堆上分配类,c++,C++,过去,每当我需要创建一个类的实例时,我都会使用new在堆上分配它(stl类和vec3和mat4等数学类除外) 然而,我只是在批判性地查看我的一些代码,并意识到从技术上讲,我可以在堆栈上生成这些类。它们不是很大,不需要在当前范围之外进行修改,等等。当我(偶尔)需要将它们传递给另一个函数时,我可以像传递指针一样轻松地使用引用 在过去,我总是默认在堆上分配,并且只在某些情况下使用堆栈,但是现在我想知道,如果默认在堆栈上分配,并且只在以下情况下使用堆,是否会更好 确实需要一个指针(即对象的生存期超过声

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

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

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

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

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

只有在需要动态分配内存时才在堆上进行分配。这意味着您不知道在编译时需要分配多少。
您在堆栈上分配所有其他时间

出于两个原因,我更喜欢在堆栈上分配。首先,在所有其他条件相同的情况下,它比heap更快。而且,解除分配是自动发生的,我不需要记住删除它(当然,有自动解除分配之类的帮助)

确实需要一个指针

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

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

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

继承需要它

为什么会这样

还有别的吗


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

您的默认行为应该是:

如果对象的寿命与特定范围一致
ie在编译时很容易确定

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

如果对象的寿命是在运行时定义的,并且超出了当前范围

然后它应该是一个动态存储持续时间对象(类似于堆)

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

我讨厌看到事物定义为堆栈与堆。因为它不能传达情况的真正语义

 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.
您应该考虑自动/动态“存储持续时间”对象。这传达了语言的正确语义

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

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

只要有可能,并不是很大的不便。当然也有例外,但作为一般规则回答您的问题:创建实例时,
new
/
new[]
的键入时间应少于1%


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

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

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

是的,但是这不应该引起太大的关注——一个如此大的类通常表明您的类存在根本性的问题。客户端友好类可以考虑在堆上创建那些巨大的、固定大小的数组。

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

在某些情况下(例如,存在一个抽象工厂或多态性克隆的深度克隆),但是它是创建该类型的工厂,并且在您可以考虑它之前,该问题经常偏离您的程序的使用。 还有别的吗

没有


原因是:

  • 它清晰、简洁,并且它的生命周期和范围已经确定
  • 减少资源消耗
  • 更少的内存相关错误或可能出错的事情
  • 速度。堆栈分配非常快。更少的锁

我想补充一点,当您希望对象的生存期超过声明的范围时。从您的列表中,我将删除除类大小参数之外的所有参数。这不是一个直接的答案,但堆栈分配确实比堆分配有一些真正的优势(例如速度、自动作用域等)。我列举了其中一些。@juanchopanza我认为这是“确实需要指针”的情况之一“一个类的大小太大(大致上)而无法在堆栈上合理分配”-这完全取决于实现。对于某些实现(微控制器等),4k的堆栈是巨大的。对于其他人来说,它绝对是微不足道的。标准没有提供任何方法让可移植代码知道它是哪一个,当你使用太多堆栈时,行为是如果你是lu,程序会被随意终止