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

operator delete[]触发Segmentation fault问题求助

基类指针指向派生类数组时delete[]触发段错误的原因及解决方案

问题代码

class A {
public:
    A() {}
    virtual ~A(){}
    double m_d;
};
class B : public A {
public:
    B() {}
    virtual ~B(){}
    int x;
};
int main()
{
    A* ptr = new B[5];
    delete[] ptr;
    return 0;
}

错误原因

这是C++标准明确规定的未定义行为:当用基类指针指向派生类对象数组,并对该指针调用delete[]时,若基类包含虚析构函数,必然会触发内存访问错误(如段错误)。

具体细节:

  • 当类存在虚函数(包括虚析构)时,对象会携带虚函数表指针(vptr)。分配派生类数组时,编译器会在数组的实际起始位置前存储元素计数,用于delete[]时遍历调用每个元素的析构函数。
  • 将new B[5]的结果赋值给A*指针时,指针会指向第一个B对象中的A子对象,而非数组的真正起始地址。
  • 调用delete[] ptr时,由于A有虚析构,编译器会尝试通过虚机制处理,但此时指针偏移错误,导致读取数组计数或调用析构函数时访问非法内存,最终触发段错误。

为什么去掉虚析构就没有异常?

这只是未定义行为下的巧合:当基类没有虚析构时,delete[]会按照基类的大小处理数组,虽然这依然不符合标准,但在这个特定场景中,内存布局的巧合让程序没有立刻崩溃。但这种写法存在严重内存泄漏风险(派生类成员不会被正确析构),绝对不能依赖。

正确解决方案

  1. 使用派生类类型指针管理数组:
int main()
{
    B* ptr = new B[5];
    delete[] ptr;
    return 0;
}
  1. 若需多态处理对象集合,使用智能指针容器:
    如果需要通过基类接口操作多个派生类对象,推荐用std::vector结合智能指针,确保每个对象的析构函数被正确调用:
#include <vector>
#include <memory>

int main()
{
    std::vector<std::unique_ptr<A>> vec;
    for (int i = 0; i < 5; ++i) {
        vec.emplace_back(std::make_unique<B>());
    }
    // 无需手动delete,智能指针会自动管理内存
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 11:55:20