C++构造函数分配失败时如何调用成员变量析构函数避免内存泄漏
C++ 构造函数中成员对象内存泄漏处理方案
现有代码的问题
你当前直接手动调用~UnLabeledList()的写法是严重错误的:
成员对象
UnLabeledList的生命周期由外层image类管控,当构造函数抛出异常时,C++标准规定所有已经完成构造的成员对象会自动按构造逆序调用析构函数,你手动调用一次之后系统又会自动调用第二次,会直接导致双重释放(double free),触发未定义行为。
正确处理方案
方案1:依赖C++构造异常自动清理机制(首选,前提是linked_list析构实现正确)
你完全不需要手动处理UnLabeledList的销毁,只要你的linked_list析构函数能正确释放自身存储的所有节点,直接删掉手动调用析构的代码即可。构造函数抛异常时系统会自动调用UnLabeledList的析构函数清理已经插入的节点,你只需要手动释放自己new出来的数组资源:
explicit image(int Segments) : SegArray(new int[Segments]) { Total_Segments = Segments; for (int i = 0; i < Segments; ++i) { if (!UnLabeledList.push_back(i, NOT_INIT)) { // 分配失败 delete[] SegArray; // 仅需要手动释放裸指针指向的数组 throw std::runtime_error("节点内存分配失败"); // 抛出任意你需要的异常类型即可 } SegArray[i] = NOT_INIT; } }
方案2:主动调用clear方法清理
如果你的linked_list提供了clear()方法(功能为清空所有节点、释放节点内存但保留列表对象本身可用),也可以主动调用该方法清理,该方案适配你不想抛异常、或者需要在构造函数内继续处理其他错误逻辑的场景:
if (!UnLabeledList.push_back(i, NOT_INIT)) { UnLabeledList.clear(); // 主动释放所有已插入的节点 delete[] SegArray; // 此处可选择抛异常,或执行其他错误处理逻辑 throw; }
方案3:RAII规范优化(推荐长期使用)
不要用裸指针管理数组资源,直接用std::vector<int>替代int* SegArray,你连手动释放数组的代码都不需要写,构造失败时所有资源都会自动被清理:
class image { public: linked_list<int, int> UnLabeledList; std::vector<int> SegArray; int Total_Segments = 0; explicit image(int Segments) : SegArray(Segments, NOT_INIT) { Total_Segments = Segments; for (int i = 0; i < Segments; ++i) { if (!UnLabeledList.push_back(i, NOT_INIT)) { // 不需要手动释放任何资源,抛异常即可自动完成所有清理 throw std::runtime_error("节点内存分配失败"); } } }; };
内容的提问来源于stack exchange,提问作者Sholy
相关产品推荐
相关产品推荐

