【问题标题】:How do I choose heap allocation vs. stack allocation in C++?如何在 C++ 中选择堆分配与堆栈分配?
【发布时间】:2011-11-01 21:27:37
【问题描述】:

将其与其他语言区分开来的 C++ 功能之一是能够将复杂对象分配为成员变量或局部变量,而不必总是使用 new 分配它们。但这会导致在任何给定情况下选择哪个的问题。

是否有一些好的标准来选择如何分配变量?什么时候应该将成员变量声明为直接变量而不是引用或指针?我什么时候应该使用new 分配变量而不是使用在堆栈上分配的局部变量?

【问题讨论】:

  • 你明白值和指针有不同的语义吗?这应该是您的第一个决策点。
  • @R.MartinhoFernandes:我很清楚这一点。但是在几乎所有可以拥有值语义的地方,你也可以拥有指针语义。毕竟指针只是一个值。

标签: c++ memory-management scope c++11 software-design


【解决方案1】:

使其有别于其他语言的 C++ 特性之一

... 是您必须手动进行内存分配。但是让我们把它放在一边:

  • 当一个对象必须是长期存在的,即必须超过某个范围,并且成本高昂或无法复制或移动时,在堆上分配,
  • 当对象很大时在堆上分配(如果为了安全起见,较大可能意味着几千字节)以防止堆栈溢出,即使该对象只是暂时需要,
  • 如果您使用的是pimpl (compiler firewall) idiom,则在堆上分配,
  • 在堆上分配可变大小的数组,
  • 否则在堆栈上分配,因为这样更方便。

请注意,在第二条规则中,“大对象”是指类似

char buffer[1024 * 1024];  // 1MB buffer

但不是

std::vector<char> buffer(1024 * 1024);

因为第二个实际上是一个非常的对象,其中包含一个指向堆分配缓冲区的指针。

关于指针与值成员:

  • 如果需要堆分配,请使用指针,
  • 如果要共享结构,请使用指针,
  • 为多态使用指针或引用,
  • 如果您从客户端代码中获取对象并且客户端承诺使其保持活动状态,请使用引用,
  • 在大多数其他情况下使用值。

当然建议在适当的情况下使用智能指针。请注意,您可以在堆分配的情况下使用引用,因为您始终可以delete &amp;ref,但我不建议这样做。引用是伪装的指针,只有一个区别(引用不能为空),但它们也表示不同的意图。

【讨论】:

  • +1,但我认为我们应该提及RVO 作为您的第一点。这使得很多情况下你的观点都是正确的,仍然可以在堆栈上分配(即一些返回某个对象的辅助函数)。
  • +1 您还可以在编译时无法确定具体类型的情况下添加多态上下文。尽管多态性并不一定意味着动态分配。
  • 这并没有解决成员变量是否应该是指针或值包含。还有像 pimpl 成语这样的事情需要考虑。
  • @Omnifarious:添加了一些关于何时使用指针成员的提示。
【解决方案2】:

larsmans 的回答没什么可补充的。

在堆栈上分配通常可以简化资源管理,您不必为内存泄漏或所有权等问题而烦恼。GUI library 是围绕这一观察构建的,检查“一切都属于某处”和“谁拥有小部件”。

如果您在堆栈上分配所有成员,那么默认的复制 ctor 和默认的 op= 通常就足够了。如果你在堆上分配成员,你必须小心你如何实现它们。

如果你在栈上分配成员变量,成员的定义必须是可见的。如果您在堆上分配它,那么您可以转发声明该成员。我个人喜欢前向声明,它减少了依赖。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-06
    • 2011-05-28
    • 2011-09-06
    • 2013-10-20
    • 1970-01-01
    • 2012-06-26
    • 1970-01-01
    相关资源
    最近更新 更多