C++堆栈与堆分配

C++ stack vs heap allocation

本文关键字:分配 堆栈 C++      更新时间:2023-10-16

我想知道什么时候应该在C++中的堆栈上分配一个类?我有很强的Java背景,在Java中,所有类都是使用new关键字在堆上分配的。在C++中,我可以在堆栈和堆分配之间进行选择,但现在引入了智能指针,用std::unique_ptr分配所有不转移所有权的东西更有意义。

我真的想不出在任何情况下,使用堆栈分配是必要的或更好的。也许是为了在嵌入式系统中进行某种优化?

只要函数范围-或函数内的控制块(如forwhileif等)的范围-与对象所需的生存期很匹配,就使用自动(堆栈)分配。这样,如果对象拥有/控制任何资源,例如动态分配的内存、文件句柄等,那么在析构函数调用过程中,这些资源将在保留该范围时被释放。(在以后某个不可预测的时间,当垃圾收集器结束时,不会发生这种情况)。

只有在明确需要时才使用new,例如:

  • 需要对象的寿命超过功能范围,

  • 将所有权移交给其他代码

  • 有一个指向基类的指针容器,然后可以对其进行多态处理(即使用虚拟调度来实现派生类函数),或者

  • 一个特别大的分配会占用堆栈的大部分(您的操作系统/进程将"协商"一个限制,通常在1-8兆字节以上的范围内)

    • 如果这是您使用动态分配的唯一原因,并且您确实希望对象的生存期与函数中的作用域绑定,则应使用本地std::unique_ptr<>来管理动态内存,并确保无论您如何离开作用域都会释放它:通过returnthrowbreak等。(您也可以在class/struct中使用std::unique_ptr<>数据成员来管理对象拥有的任何内存。)

Mathieu Van Nevel在下面评论了C++11移动语义——相关性在于,如果堆栈上有一个小的管理对象,它控制着大量的动态分配(堆)内存,move语义为管理对象何时将其资源移交给其他代码拥有的另一个管理对象(通常是调用者,但可能是对象的其他容器/寄存器)提供了额外的保证和细粒度控制。这种切换可以避免堆上的数据被复制/复制,即使是暂时的。此外,省略返回值优化通常允许在一些内存中直接构建名义上自动/堆栈托管的变量,而不是稍后复制到那里。

在大型代码库中,我们对简单的结构对象使用堆栈分配,而对更复杂的类(涉及多态性、内存所有权等),我们总是使用动态分配。