哈希表作业内存泄漏排查: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函数未对应释放会泄漏 - 尝试显式调用析构函数触发报错
- run()函数中用
解决方案
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
相关产品推荐
相关产品推荐

