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

C++删除第二个对象时触发崩溃 双重释放问题排查修复

崩溃根因

程序第二次执行delete switch1时崩溃的核心原因是双重内存释放(Double Free):

  • 代码中仅通过new Lamp{numberClick}在堆上创建了1个Lamp实例,该实例的内存地址被同时传入switch0、switch1两个Switch对象,保存在各自的lamp成员指针中
  • Switch类的析构函数固定执行delete lamp;逻辑,没有做对象所有权的区分
  • 执行delete switch0时,switch0的析构函数已经释放了Lamp实例占用的堆内存,此时switch1中存储的lamp指针已经成为指向已回收内存的野指针
  • 后续执行delete switch1时,析构函数再次对已经失效的野指针执行delete操作,直接触发内存访问违规,导致程序崩溃

除了运行时崩溃问题,原代码还存在4处会导致编译失败、逻辑异常的笔误:

  • Lamp::click()方法关灯分支的计数器拼写错误:conter++应为counter++
  • main函数创建switch1的语句缺失右括号:Switch* switch1 = new Switch(lamp 末尾需补)
  • 操作switch0的语句变量名大小写错误:Switch0->push();应为switch0->push();(C++变量名区分大小写)
  • 操作switch1的方法调用缺失括号:switch1->push应为switch1->push();
修正与规避方案

针对这类裸指针共享导致的内存问题,可按以下规则处理:

  • 明确对象所有权边界:如果多个对象需要共享同一个堆实例,绝对不要在每个持有指针的对象析构时都执行释放操作,仅由持有实例所有权的模块负责内存回收。本场景中Lamp实例在main函数中创建,所有权归属main函数,应当删除Switch类析构函数中的delete lamp;逻辑,等两个Switch对象都释放完成后,再在main函数中单独执行delete lamp;

    修正后的核心逻辑示例:

    // Switch类不持有Lamp所有权,移除析构中的delete逻辑
    ~Switch() = default;
    
    // main函数末尾按创建逆序释放资源
    delete switch1;
    delete switch0;
    delete lamp;
    
  • 优先使用现代C++智能指针替代裸指针:
    • 独占资源场景使用std::unique_ptr,编译期即可阻止所有权拷贝,从语法层面避免重复释放
    • 共享资源场景使用std::shared_ptr,内部通过引用计数自动管理内存,最后一个持有指针的对象销毁时才会释放实例,彻底杜绝双重释放问题
  • 裸指针场景下做好防御:执行delete操作后立刻将指针赋值为nullptr,由于C++标准规定delete空指针是无操作的安全行为,可避免野指针误释放
  • 配套工具提前排查问题:编译时加上-Wall -Wextra参数,提前捕获拼写、未初始化等低级错误;测试阶段使用内存检测工具,可精确定位内存重复释放、越界访问等隐蔽问题

内容的提问来源于stack exchange,提问作者Simone Polizzi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 09:48:15