C++中析构函数调用顺序异常问题咨询
咱们一步一步拆解你的代码执行流程,就能明白这个析构顺序到底是怎么回事了~
代码执行全流程解析
先逐个追踪每个对象的生命周期和对应的构造/析构行为:
1. 主函数初始化 ob
myClass ob;
这一行调用默认构造函数,静态变量y从0变为1,输出constr 1。这个ob是主函数的局部对象,生命周期从这里开始,直到主函数结束才会被销毁。
2. 调用函数 f(ob)
函数f的参数是值传递,这意味着必须把实参ob拷贝一份给函数的形参ob:
- 触发拷贝构造函数,
y变为2,输出copy-c 2。这个形参对象是f函数的局部对象,只在f函数执行期间存在。
接下来f执行return ob;:
- 因为函数返回的是对象值,编译器会创建一个临时对象来存储返回值,把形参
ob拷贝到这个临时对象中,再次触发拷贝构造函数,y变为3,输出copy-c 3。
3. f函数执行完毕
f函数的局部对象(也就是那个拷贝出来的copy-c2)会被立即销毁,调用析构函数,输出destr copy-c2。这是C++的固定规则:函数的局部对象在函数退出时必然被销毁,不管它是不是被用来生成返回值。
4. 用返回值初始化 s
你写的myClass s=f(ob);是直接初始化s,这里编译器会把存储返回值的临时对象直接“转化”为s——也就是说,s就是那个copy-c3的对象,不需要额外调用拷贝构造函数。这是C++对临时对象的优化规则,避免不必要的拷贝。
5. 主函数执行完毕,销毁局部对象
主函数的局部对象销毁顺序遵循后构造的先析构原则:
s的构造时间晚于ob(准确说是用返回的临时对象初始化,相当于s的创建时机在ob之后),所以先销毁s,输出destr copy-c3。- 然后销毁最早构造的
ob,输出destr constr1。
为什么你觉得“不符合常规”?
你可能误以为返回的临时对象会提前被销毁,或者形参的销毁时机和返回值有关,但实际上:
- 函数形参的销毁时机是固定的——函数退出时立刻销毁,所以
copy-c2必然是第一个被销毁的。 - 那个“临时对象”并没有被提前销毁,它只是被用来直接初始化
s,所以你看到的destr copy-c3其实是s的析构,而不是临时对象的提前销毁。
如果你的编译器开启了返回值优化(RVO/NRVO),还会跳过临时对象的拷贝步骤,直接在s的内存位置构造返回值,这时候输出会少一个copy-c3的打印,但你的输出是未开启优化的情况,所以我们按当前输出解析。
内容的提问来源于stack exchange,提问作者Sergiu Talmacel
相关产品推荐
相关产品推荐

