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

C++ new分配指针内存泄漏且delete崩溃的修复方法

C++ 堆指针场景内存泄漏修复方案

现有代码核心问题

  • DoClone中new出的Dengue对象存入list返回时,确实不能在函数内提前delete——list只存储指针地址,不会拷贝堆上的实际对象,提前delete会直接让list内元素变成悬空指针,访问必然崩溃。但当前代码没有明确这些堆对象的释放责任主体,是内存泄漏的直接原因。
  • DoDie的释放顺序完全错误:先把m_dna赋值为NULL,再delete空指针,根本没有释放m_dna原本指向的堆内存,直接造成泄漏;同时memset硬写长度4,如果m_protein是int等非1字节类型的数组,既无法完整清零数组,还存在内存操作风险。
  • DoClone中对m_dna直接做指针浅拷贝,导致原对象、两个克隆对象三个指针指向同一块堆内存,只要任意一个对象释放这块内存,剩下两个对象持有的都是悬空指针,这也是你之前执行delete操作就崩溃的核心诱因。
  • 你用Virus*基类指针存储Dengue派生类对象,如果Virus的析构函数不是虚函数,后续delete基类指针时不会调用派生类析构逻辑,同样会泄漏内存甚至崩溃。

具体修复步骤

1. 修正DoDie的释放逻辑

严格遵循「先释放指针指向的内存,再置空指针」的顺序,同时修正内存操作长度:

// 首先确保Virus类定义了虚析构函数
class Virus {
public:
    virtual ~Virus() = default; // 加这行,保证派生类对象能被正确析构
    // 其他原有成员...
};

void DoDie()
{
    // 先释放持有的堆内存
    delete this->m_dna;
    // 释放完成再置空,避免悬空指针
    this->m_dna = nullptr;
    // 用sizeof自动计算数组长度,不要硬编码数值
    memset(this->m_protein, 0, sizeof(this->m_protein));
    this->m_resistance = 0;
}

2. 修复DoClone的浅拷贝问题

克隆新对象时,m_dna不能直接拷贝指针地址,要做深拷贝,保证每个对象持有独立的内存副本,避免重复释放:

list<Virus*> DoClone() 
{
    list<Virus*> l;

    Dengue *d1 = new Dengue(1), *d2 = new Dengue(1);
    for (int i = 0; i < 4; i++)
        d1->m_protein[i] = m_protein[i];
    // m_dna做深拷贝,根据m_dna的实际类型选择实现:
    // 如果m_dna是自定义类型指针,直接调用拷贝构造生成新对象:
    // d1->m_dna = new DnaType(*m_dna);
    // 如果m_dna是C风格字符串:
    // d1->m_dna = new char[strlen(m_dna) + 1];
    // strcpy(d1->m_dna, m_dna);
    d1->m_dna = DeepCopyDna(m_dna); // 替换为你实际业务的深拷贝逻辑
    d1->m_resistance = m_resistance;

    for (int i = 0; i < 4; i++)
        d2->m_protein[i] = m_protein[i];
    d2->m_dna = DeepCopyDna(m_dna);
    d2->m_resistance = m_resistance;

    l.emplace_back(d1);
    l.emplace_back(d2);
    return l;
}

3. 明确内存释放责任

DoClone返回的list中存储的堆指针,释放责任由list的持有方承担,在list生命周期结束前必须遍历完成内存释放:

// 调用DoClone的业务代码示例
list<Virus*> cloneList = someVirus.DoClone();
// 执行业务逻辑...
// 用完后必须逐元素释放
for (Virus* virusPtr : cloneList) {
    virusPtr->DoDie(); // 先释放对象内部持有的m_dna等堆内存
    delete virusPtr;   // 再释放Virus/Dengue对象本身
}
cloneList.clear();

关键避坑点

  • 不要在返回存储堆指针的容器前,在函数内释放指针,容器不会托管你手动new出来的堆内存。
  • 类持有堆指针成员时,要么明确禁止拷贝/赋值(将拷贝构造、赋值运算符标记为=delete),要么必须实现深拷贝逻辑,绝对不要默认浅拷贝导致多个指针指向同一块内存。
  • 基类指针指向派生类对象的场景,基类必须声明虚析构函数,否则delete基类指针属于未定义行为。

内容的提问来源于stack exchange,提问作者Lưu Phạm Thị

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 16:48:52