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

派生类对象销毁时父子析构均调用:双释放为何未触发段错误?

问题分析与解答

为什么双重释放未触发段错误?

  • 双重释放属于未定义行为,C++标准没有强制要求这种场景必须触发段错误,实际表现完全依赖操作系统内存管理机制和编译器实现:
    • 部分内存分配器在释放内存后,不会立刻将内存归还给操作系统,只是标记为"已释放"但仍保留在进程地址空间内。再次释放时,分配器可能仅重复标记,不会立刻引发崩溃,但这会造成内存损坏,后续操作可能出现随机崩溃、数据错乱等不可预料的问题。
    • 你当前的测试环境刚好没触发崩溃,但这绝不代表代码正确,未定义行为随时可能在不同环境、不同运行时机下爆发问题。
  • 代码还存在一个隐藏隐患:Parent用std::malloc分配内存,却用delete释放。malloc/free与new/delete是两套独立的内存管理机制,混用本身就属于未定义行为,会额外增加风险。

解决方案确认

你的思路完全正确:Child仅负责释放自身分配的动态内存,Parent的成员mem由Parent的析构函数单独处理。具体修正步骤如下:

  1. 移除Child类中的析构函数,它无需处理父类的资源。销毁Child对象时,会先调用Child的析构(若存在),再自动调用Parent的析构,由父类负责清理自己的成员。
  2. 修正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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 14:42:48