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

哈希表作业内存泄漏排查:CovidDB析构函数未调用问题

哈希表内存泄漏问题排查与解决

问题现状

  • 作业要求:使用原始指针实现哈希表(链地址法,基于二维std::vector)存储CSV数据,禁止引入<memory>库
  • 程序功能正常,但valgrind检测到大量内存泄漏:
==4044056== LEAK SUMMARY:
==4044056==    definitely lost: 17,511,840 bytes in 243,220 blocks
==4044056==    indirectly lost: 1,257,494 bytes in 39,329 blocks
==4044056==      possibly lost: 391 bytes in 6 blocks
==4044056==    still reachable: 20,626 bytes in 292 blocks
==4044056==         suppressed: 0 bytes in 0 blocks
  • 核心问题:CovidDB类析构函数未执行(添加的cout无输出),原因是退出时调用std::exit(EXIT_SUCCESS)直接终止程序,局部dataBase对象无法触发自动析构
  • 其他潜在泄漏点:
    • run()函数中用new创建的DataEntry* data未释放
    • add函数中new DataEntry(*entry)分配的内存,若remove函数未对应释放会泄漏
    • 尝试显式调用析构函数触发报错

解决方案

1. 修复析构函数未执行的核心问题

std::exit()会直接终止进程,不会调用局部对象的析构函数,必须替换退出逻辑:

  • 改用标志位控制循环结束,让run()函数自然返回,局部dataBase对象会自动调用析构函数
  • 示例代码:
void run() {
    CovidDB dataBase;
    bool shouldExit = false;
    while (!shouldExit) {
        int choice;
        // 处理用户输入选择逻辑
        if (choice == 退出选项) {
            shouldExit = true;
            // 绝对不要调用std::exit
        }
        // 其他业务逻辑
    }
    // 函数结束时,dataBase自动触发析构
}
  • 禁止显式调用析构函数:手动调用会导致对象被重复销毁,触发未定义行为,完全不可取

2. 释放run()中new创建的DataEntry指针

run()中每次用new创建DataEntry*后,使用完毕必须调用delete释放,无论是否添加成功:

// run()中示例片段
DataEntry* data = new DataEntry(...); // 分配内存
if (dataBase.add(data)) {
    // 若add内部已复制对象(如new DataEntry(*entry)),释放原指针
    delete data;
} else {
    // 添加失败也要释放
    delete data;
}

3. 完善哈希表内存管理逻辑

(1)正确实现析构函数遍历释放

确保CovidDB析构函数遍历二维vector的每条链表,逐个释放节点:

CovidDB::~CovidDB() {
    // 假设哈希表成员为std::vector<std::vector<DataEntry*>> hashTable;
    for (auto& chain : hashTable) {
        for (DataEntry* entry : chain) {
            delete entry;
            entry = nullptr; // 避免野指针
        }
        chain.clear();
    }
    hashTable.clear();
    // 可保留cout验证执行:
    std::cout << "CovidDB析构函数已执行" << std::endl;
}

(2)remove函数必须释放对应节点内存

找到要删除的DataEntry指针时,先调用delete释放内存,再从链表中移除指针:

bool CovidDB::remove(const std::string& key) {
    int index = hashFunction(key);
    auto& chain = hashTable[index];
    for (auto it = chain.begin(); it != chain.end(); ++it) {
        if ((*it)->getKey() == key) {
            delete *it; // 先释放内存
            chain.erase(it); // 再移除指针
            return true;
        }
    }
    return false;
}

(3)add函数内存责任明确

如果add函数通过new DataEntry(*entry)复制对象存入哈希表,那么传入的原始entry指针的释放责任由调用者承担(比如run()中创建的data指针要手动delete),避免重复释放或泄漏

4. 验证修复效果

修改完成后,重新用valgrind检测:

valgrind --leak-check=full ./your_program

检查LEAK SUMMARY中definitely lost和indirectly lost是否变为0

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 12:02:07