You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:07:06