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[]会按照基类的大小处理数组,虽然这依然不符合标准,但在这个特定场景中,内存布局的巧合让程序没有立刻崩溃。但这种写法存在严重内存泄漏风险(派生类成员不会被正确析构),绝对不能依赖。
正确解决方案
- 使用派生类类型指针管理数组:
int main() { B* ptr = new B[5]; delete[] ptr; return 0; }
- 若需多态处理对象集合,使用智能指针容器:
如果需要通过基类接口操作多个派生类对象,推荐用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
相关产品推荐
相关产品推荐

