堆栈属性:
class MyStackClass
{
public:
MyStackClass (int a)
{
myType.create (a); // "create" is an alternative to Type constructor
}
private:
Type myType;
};
堆属性:
class MyHeapClass
{
public:
MyHeapClass (int a) { myType = new Type (a); }
~MyHeapClass () { delete myType; }
...
private:
Type *myType;
};
我只在必要时使用动态分配,例如,动态数组,不存在的变量等等。但是我发现有些程序员在没有必要的情况下对属性使用堆分配。是什么原因?我的意思是,它比堆栈分配更昂贵的堆分配。那么,我何时应该使用“堆”方式而不是“堆栈”方式?
感谢。
编辑:
假设“MyHeapClass”具有复制构造函数,并operator =
来满足需求。
答案 0 :(得分:2)
这是一个基本上基于意见的答案。但是我会提出一些你应该在这里考虑的事项。此外,C ++标准没有提到堆栈或堆,只提到变量范围和生命周期。因此,这个答案是特定于C ++实现实际使用典型堆栈和堆的系统的实现。
堆栈通常比堆小得多。通常在几兆字节的范围内。另一方面,堆在现代系统上通常是几千兆字节。
如果你把更多的东西放在堆栈上,那么你的软件可能会崩溃,或者更糟糕的是开始无法预测。因此,在堆上分配非常大的对象通常会更好。
另一方面,如前所述,分配堆对象会有很大的开销,尽管有一个明显的优势,即分配可能会以语言定义的方式失败,您可以处理而不是崩溃,或者更糟糕的是堆栈分配失败。
其次,我们需要提高传递对象的成本。具体来说,堆对象通常由指针或引用处理,因此传递它们非常便宜。堆栈对象也可以这样做,除非它们必须存在的时间长于当前范围。在这种情况下,它们必须被复制(除了移动语义或RVO),否则您将面临使用过期的堆栈帧,坏消息和未定义的行为。
最后,我们需要调出不可预测大小的对象,如数组,向量等。据我所知,在标准中没有一种简单的方法可以在堆栈上分配对象或运行时已知大小。非标准alloca允许这样做,但在各种方面都很危险。
在时序特别关键的部分,例如真正的需求或严格的性能关键循环,堆分配的开销在多种方面是不可取的。因此,人们可能更倾向于堆栈分配。
然而,有各种各样的解决方法,包括使用具有保证O(1)时间复杂度的内存分配器预先分配时间cricial代码可能提前使用的最大内存量(这可能由于缓慢和低效的内存使用)或使用对象池或竞技场分配器来快速回收用于避免现在分配的相同类型的内存旧堆对象。
这些要点总结了一般规则,即大型或不可预测且可能大型的对象通常应该在堆上找到自己,而对象虽然很小,特别是如果它们属于本地范围且不需要过多地传递应该进入堆栈。
然而,这不是一个硬性规则,而且有很多例外。在每种情况下,程序员必须考虑对象的最佳位置。
答案 1 :(得分:1)
使用C ++ 11及更高版本,您几乎不应该使用显式(调用new
和delete
)堆分配:它更危险。
使用堆分配进行堆分配不是用C ++编程的好方法。 只有当您没有其他选择时,您才应(明确地)使用动态分配。
可能存在或不存在的动态数组和变量需要动态分配,但C ++标准提供了轻松处理它们的类(vector
,unique
/ shared
/ weak_ptr
和optional
与C ++ 17)。
当然,这些类使用堆分配,但它们安全地进行。
指针的一个用途是标准容器中的非可复制类,以及容器中的多态类型。 无论如何,你应该始终将资源管理(指针或文件......)包装在一个类中(参见RAII习语)
答案 2 :(得分:0)
在某些语言中,变量是从堆中分配的,如C#和Java。
C ++语言提供了更多选择,例如本地分配(您称为堆栈),堆和全局/自动位置。
Java和C#有垃圾收集,而C ++没有。具有垃圾收集的语言允许第三方任务定期通过堆并清理(重新排序)内存,以便可以使用更多内存。 C ++中不存在此任务。
C ++自由允许一个人声明变量并在不使用它们之后将它们删除(例如离开范围)。需要存在于声明范围之外的变量将在堆上分配(例如,创建许多函数使用的变量)。这消除了依赖垃圾收集器的需要。
在内存受限的系统上,例如嵌入式设备,内存碎片是一个很大的问题。某些系统(例如手机)可以进行电源循环以对存储器进行碎片整理。其他系统,例如医疗设备和航空航天设备,功率循环不是用于对存储器进行碎片整理的优选方法。 (想象一下,在高空飞行中重新启动飞机的计算机系统。)所以我的想法是不使用堆内存并使用其他方法。堆栈分配就是其中之一。
在一些关键的计时系统中,会议活动至关重要。使垃圾收集器以随机间隔运行意味着可能会错过其中一些关键事件。堆内存的碎片在这些系统中也是有害的。因此,需要某种方式来分配变量而不会导致碎片整理。 "堆栈"分配方法有助于消除这个问题。