堆栈属性:
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 =
以满足需求。
最佳答案
这基本上是一个基于意见的答案。不过,我会在这里提出一些您应该考虑的事项。此外,C++ 标准没有提及堆栈或堆,仅提及变量作用域和生命周期。因此,这个答案是特定于其 C++ 实现实际上使用典型堆栈和堆的系统的实现。
大小限制
堆栈通常比堆小得多。通常在几兆字节的范围内。另一方面,现代系统上的堆通常有几 GB。
如果您在堆栈上放置的内容超出了允许的范围,您的软件可能会崩溃,或者更糟糕的是开始出现不可预测的行为。因此,通常最好在堆上分配非常大的对象。
另一方面,正如您所提到的,分配堆对象会产生大量开销,尽管有一个显着的优点,即分配可能会以语言定义的方式失败,您可以处理它,而不是崩溃或更糟的情况堆栈分配失败。传递和返回
其次,我们需要提高传递对象的成本。具体来说,堆对象通常由指针或引用处理,因此传递这些对象非常便宜。对于堆栈对象也可以执行相同的操作,除非它们的生存时间必须长于当前范围。在这种情况下,它们必须被复制(移动语义或 RVO 除外),否则您将面临使用过期的堆栈帧、坏消息和未定义的行为。
可变长度对象
最后,我们需要调出大小不可预测的对象,例如数组、 vector 等。据我所知,没有一种简单的方法可以在标准中的堆栈上分配对象或运行时已知大小。非标准分配允许这样做,但在很多方面都是危险的。
时间
在时序特别关键的部分中,例如真正的时序要求或严格的性能关键循环,堆分配的开销在多种方面都是不受欢迎的。因此,人们可能会更倾向于堆栈分配。
然而,对此有多种解决方法,包括预先分配时序关键代码可能使用的最大内存量,使用保证 O(1) 时间复杂度的内存分配器(这通常可能没有用,因为缓慢且低效的内存使用)或使用对象池或竞技场分配器来快速回收用于避免现在分配的相同类型的内存旧堆对象。
结论
这些点都概括为一个一般规则,即大型对象或不可预测且可能较大的对象通常应该在堆上找到自己,而小型对象,特别是当它们属于本地范围并且不需要时传递的太多内容应该放在堆栈上。
然而,这并不是一个硬性规定,并且有很多异常(exception)情况。在每种情况下,程序员都必须考虑对象的最佳位置。
关于C++ - 堆与堆栈属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36211406/