You need to enable JavaScript to run this app. C++20中new表达式构造函数抛异常是否会导致内存泄漏
优惠活动
大模型
产品
解决方案
定价
更多

C++20中new表达式构造函数抛异常是否会导致内存泄漏

核心问题解答

该程序不存在内存泄漏

你给出的C++程序完全没有内存泄漏问题。
常规new表达式的执行逻辑是固定的:

  • 先为目标对象申请对应大小的原始内存,拿到内存首地址
  • 在这块内存上按固定顺序完成对象构造:先构造所有基类子对象,再按类内声明顺序构造所有非静态成员子对象,最后执行类的构造函数体
  • 如果构造流程的任意环节抛出异常,会自动执行两步清理:
    • 从最后一个完成构造的子对象开始,逆序调用所有已构造子对象的析构函数——这就是你看到输出~S1的原因
    • 无条件释放第一步申请到的整块原始内存

清理完成后,异常会直接向上传递,new表达式不会将内存地址赋值给你代码里的s2变量,你根本无法拿到这块已经被回收的内存地址,自然不存在内存泄漏。
S2自身的析构函数没有被调用,是完全符合语言规则的:S2的整体构造从未完成,对象的生命周期从未正式开启,不满足析构函数的合法触发时机。

该行为是C++标准强制保障的,不存在未定义/未指定行为

从C语言诞生到C20,这套清理流程一直是标准明确要求的强制规则,所有执行步骤都是确定性的:

  • 标准明确规定,new表达式的内存分配、构造、异常清理是严格配对的:只要构造函数抛出异常,运行时必须匹配之前为对象申请内存时调用的分配函数,完整释放整块内存。哪怕你为S2自定义了类级别的operator new和operator delete,编译器也会在构造异常时自动调用对应的operator delete完成释放,不需要用户手写额外的清理代码。
  • 全流程的执行顺序没有留给编译器自由裁量的空间:子对象的构造顺序、异常中断时的逆序析构顺序、析构完成后的内存释放时机,都有明确的规则要求,不存在实现定义的行为。
  • 只有在使用定位new(placement new)手动调用构造函数的场景下,语言才不会自动帮你配对内存释放逻辑——这种场景下如果构造抛出异常,需要开发者手动完成已构造子对象的析构和内存释放。你代码里使用的是常规new表达式,不涉及这类特殊场景。

内容的提问来源于stack exchange,提问作者Andrew Tomazos

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.01 19:54:04