派生类对象销毁时父子析构均调用:双释放为何未触发段错误?
问题分析与解答
为什么双重释放未触发段错误?
- 双重释放属于未定义行为,C++标准没有强制要求这种场景必须触发段错误,实际表现完全依赖操作系统内存管理机制和编译器实现:
- 部分内存分配器在释放内存后,不会立刻将内存归还给操作系统,只是标记为"已释放"但仍保留在进程地址空间内。再次释放时,分配器可能仅重复标记,不会立刻引发崩溃,但这会造成内存损坏,后续操作可能出现随机崩溃、数据错乱等不可预料的问题。
- 你当前的测试环境刚好没触发崩溃,但这绝不代表代码正确,未定义行为随时可能在不同环境、不同运行时机下爆发问题。
- 代码还存在一个隐藏隐患:
Parent用std::malloc分配内存,却用delete释放。malloc/free与new/delete是两套独立的内存管理机制,混用本身就属于未定义行为,会额外增加风险。
解决方案确认
你的思路完全正确:Child仅负责释放自身分配的动态内存,Parent的成员mem由Parent的析构函数单独处理。具体修正步骤如下:
- 移除
Child类中的析构函数,它无需处理父类的资源。销毁Child对象时,会先调用Child的析构(若存在),再自动调用Parent的析构,由父类负责清理自己的成员。 - 修正
Parent中内存分配与释放的匹配问题:要么用malloc对应free,要么用new对应delete。推荐使用C++原生的内存管理方式,比如数组分配用new[],释放用delete[]。
修正后的代码示例:
#include <cstdlib> class Parent { protected: int* mem = new int[5]; // 用new[]分配数组,匹配delete[] public: Parent() {}; virtual ~Parent() { delete[] mem; } }; class Child: public Parent { public: Child() {}; // 移除Child的析构函数,无需处理父类资源 }; int main(void) { Child* c = new Child(); delete(c); }
更推荐用智能指针(如std::unique_ptr<int[]>)管理动态内存,彻底避免手动释放的风险:
#include <memory> class Parent { protected: std::unique_ptr<int[]> mem = std::make_unique<int[]>(5); public: Parent() {}; virtual ~Parent() = default; // 智能指针自动释放内存,无需手动写析构 }; class Child: public Parent { public: Child() {}; }; int main(void) { Child* c = new Child(); delete(c); }
内容的提问来源于stack exchange,提问作者Ye Naing Oo
相关产品推荐
相关产品推荐

