何时以及为什么在堆C++上声明成员变量
When and why to declare member variables on the heap C++
好吧,所以我对C++编程很陌生,几天来我一直在四处寻找这个问题的决定性答案。什么时候应该在堆上声明成员变量,而不是在堆栈上声明?我发现的大多数答案都涉及其他问题,但我想知道什么时候最好对成员变量使用堆,以及为什么最好对成员进行堆而不是堆叠。
首先要掌握两个重要概念:
-
人们应该避免用"堆"answers"堆栈"来思考。这些是编译器/平台的实现细节,而不是语言的细节1相反,从对象寿命的角度思考:对象的寿命应该与其"父对象"的寿命相对应,还是应该比它更长寿?如果需要后者,则需要使用
new
(直接或间接)来动态分配对象。 -
成员变量始终与其父级具有相同的生存期。成员变量可以是一个指针,它所指向的对象很可能具有独立的生存期。但是指向的对象不是成员变量。
然而,你的问题没有一个普遍的答案。严格地说,除非有充分的理由,否则不要动态分配。正如我上面暗示的,这些原因通常对应于生命周期需要与其"父"不同的情况。
1.事实上,C++标准并没有真正谈论"堆"answers"堆栈"。在优化或总体考虑性能时,它们很重要,但从程序功能的角度来看,它们大多无关紧要
成员变量是类本身的成员。它们都没有打开堆也不在堆栈上,或者更确切地说,它们是类所在的位置
添加间接级别和分配堆上单独的成员:多态性(如果成员的类型不总是一样)是迄今为止最常见的。
为了弄清楚一些术语:您所称的heap
和stack
描述对象的生存期。第一个表示生存期为dynamic
,第二个为automatic
,第三个(您没有提及)为static
。
通常,当一个对象的生存期应该超过它创建的范围时,你需要它的dynamic
生存期。另一种常见的情况是,当你希望它在不同的父对象之间共享时。此外,当您使用面向对象的设计(使用大量多态性,不使用值)时,动态生命周期也是必要的,例如Qt
。
一个需要动态生命周期的成语就是皮条成语。
大多数通用编程库都更侧重于值和值语义,因此您不会太多地使用动态绑定,自动生存期也变得更加常见。
还有一些例子表明,由于更具体的实施原因,需要动态分配:
- 动态调整对象(容器)大小
- 处理不完全类型(参见皮条客习语)
- 类型的易为空性
所有这些都只是一般性的指导方针,必须根据具体情况做出决定。通常,比起动态对象,更喜欢自动对象。
堆栈指call stack
。函数调用、返回地址、参数和局部变量都保留在调用堆栈中。无论何时传递参数或创建局部变量,都可以使用堆栈内存。堆栈只有临时存储。一旦当前函数超出范围,就不能再访问参数的任何变量。
堆是一个用于动态分配的大型内存池。使用new
运算符分配内存时,会从堆中分配此内存。您希望在创建对象时分配堆内存,而这些对象不希望在当前函数终止(失去作用域)后丢失。对象被存储在堆中,直到空间被delete
或free()
释放。
考虑这个例子:
您实现了一个具有字段成员类头节点的链表。
每个节点都有一个字段成员next
。如果此成员的类型为Node,而不是Node*,则每个Node的大小将取决于链中该节点之后的节点数
例如,如果你的列表中有100个节点,那么你的头部成员将是巨大的。因为它将下一个节点容纳在自己内部,所以它需要有足够的大小来容纳它,下一个容纳下一个,依此类推。所以头部必须有足够的空间来容纳99个节点,然后98个,依此依此类推…
您希望避免这种情况,所以在这种情况下,最好在每个节点中都有指向下一个节点的指针,而不是指向下一节点本身。
- 在指向现有内存地址的 hpp 文件中声明成员函数的最佳方法
- 如何使用模板声明成员函数?(不是模板类)
- 如何使用 Boost.Hana 声明成员变量
- 声明成员对象而不调用其默认构造函数
- 使用函数类型语法声明成员函数
- 尝试访问标头声明成员时出现隔离错误
- 根据二手构造函数声明成员
- C 模板明确声明成员函数值/避免了宏的问题
- 如何在基本模板类中声明成员,其中类型取决于派生类的类型
- 错误:类中没有声明成员函数
- 我可以使用相同的名称为周围作用域中的类型声明成员类型别名吗
- 从variadic模板参数声明成员变量
- 在类(C )中使用模板时未声明成员函数
- 错误:类中未声明 '' 成员函数
- 如何在指向常量地址时声明成员函数常量指针
- 何时以及为什么在堆C++上声明成员变量
- C++ 错误:未在范围内声明;成员函数
- 在不声明成员变量的情况下更改按钮颜色
- 错误 C2535:已定义或声明成员函数
- 当声明成员函数时,*New()是什么意思