C++中heap分配的对象在构造函数内创建的局部对象分配位置在哪?
class Foo { int num; }; class Bar { public: Bar() { Foo f1; } }; int main() { Bar* b = new Bar(); return 0; }
核心结论
Bar构造函数内的局部对象f1存储在栈内存,和堆上的Bar实例b没有任何关联。
存储位置的判定规则
C++中对象的存储位置完全由它的声明方式、存储周期决定,和它所在函数的用途、所属类实例的存储位置无关:
- 通过
new创建的动态存储期对象,分配在堆(自由存储区),生命周期不受作用域限制 - 函数内部定义的非静态局部变量,属于自动存储期,分配在栈内存,离开当前作用域会自动析构
你这里的f1是Bar构造函数内部定义的普通局部变量,完全符合自动存储期的判定规则——哪怕这个构造函数是用来初始化堆上的Bar实例,也不会改变f1的存储位置。
自动析构的逻辑解释
栈内存的管理粒度是「函数调用栈帧」:每次调用任意函数(包括类的构造函数)时,会在栈上划出一块独立的内存区域(栈帧),用来存储这个函数的所有局部变量、返回地址、上下文信息;函数执行结束后,这块栈帧会被整体回收,里面的所有自动对象都会自动调用析构函数完成清理。
这个逻辑和函数正在初始化的对象在堆还是栈没有关系,完全是栈内存本身的运行规则。
「Bar关联f1」的误解根源
你产生这个疑问的核心原因是混淆了类的成员变量和函数内部的局部变量:
这段代码里的f1根本不是Bar的类成员,只是构造函数内部的临时局部变量,Bar实例本身不持有任何和f1相关的存储。构造函数执行结束后,f1就已经随栈帧销毁了,不存在「堆上的Bar要关联栈上f1」的问题。
如果是Bar类内部声明了Foo类型的成员变量,那这个成员的存储位置才会和Bar实例保持一致:堆上的Bar的成员就在堆上,栈上的Bar的成员就在栈上。
常见误区澄清
很多人会误以为「构造堆对象时,构造函数内部的局部变量会被分配在堆上」,这是典型的认知偏差:函数调用的栈帧始终是分配在栈上的,和这个函数正在操作的对象在什么内存区域没有任何关系。
内容的提问来源于stack exchange,提问作者SubMachine
相关产品推荐
相关产品推荐

