为何基类指针删除单个对象与数组时delete运算符调用行为不同?
C++中delete单个对象与delete数组的operator delete调用差异解析
示例代码
#include <iostream> using namespace std; struct A { virtual ~A() { cout << "~A ";}; void operator delete(void* p) { cout << "A :: operator delete" << endl; } void operator delete[](void* p) { cout << "A :: operator delete[]" << endl; } }; struct B : A { ~B(){ cout << "~B ";} void operator delete(void* p) { cout << "B :: operator delete" << endl; } void operator delete[](void* p) { cout << "B :: operator delete[]" << endl; } }; int main() { A* ptr1 = new B; A* ptr2 = new B[2]; delete ptr1; delete [] ptr2; }
运行输出
~B ~A B :: operator delete ~B ~A ~B ~A A :: operator delete[]
行为差异原因解析
1. 单个对象的delete逻辑
当执行delete ptr1时:
- 因为基类
A声明了虚析构函数,编译器会通过虚表机制定位到对象的实际类型(B),先调用B的析构函数,再调用A的析构函数。 - 完成析构后,C++标准规定,对于多态类的单个对象删除操作,会继续通过虚表关联的机制,调用实际类型(
B)对应的operator delete,这也是输出中出现B :: operator delete的原因。
2. 数组对象的delete[]逻辑
当执行delete[] ptr2时:
- 虽然虚析构函数保证了每个数组元素都能正确调用
B和A的析构函数(因此输出两次~B ~A),但**operator delete[]并不支持虚函数动态绑定**。 - C++标准未将数组删除函数纳入虚函数体系,编译器会直接根据指针的静态类型(即
A*)来选择对应的operator delete[],而非对象的动态类型(B)。因此最终调用的是基类A的operator delete[]。 - 底层原因是:数组内存分配时,会在数组头部存储元素个数等元信息,但这些信息不包含用于动态选择
operator delete[]的虚表指针或类似机制,无法像单个对象那样完成动态绑定。
内容的提问来源于stack exchange,提问作者Hardik
相关产品推荐
相关产品推荐

