为什么派生类重载删除运算符被调用?

Why derived class overloaded delete operator called?

提问人:Hardik 提问时间:9/30/2023 更新时间:9/30/2023 访问量:79

问:

#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[]

删除基类指针 ptr1 时,将调用派生类删除运算符方法,但是在删除 ptr2(保存派生类数组的动态内存位置)时,将使用基类删除运算符方法。谁能解释这种行为?

C++ 继承删除 运算符

评论

6赞 Igor Tandetnik 9/30/2023
通过指向基类的指针删除数组是未定义的行为,即使是具有虚拟析构函数的数组也是如此。数组不像单个对象那样是多态的。
0赞 Hardik 9/30/2023
@IgorTandetnik 如果数组不是多态的,那么为什么派生类析构函数会首先调用呢?
2赞 PaulMcKenzie 9/30/2023
@Hardik为什么派生类析构函数首先调用呢? -- 未定义的行为意味着 -- 行为是未定义的。
2赞 PaulMcKenzie 9/30/2023
我获取了您的代码并在 Visual Studio 2022 中运行了它。输出为:-- .这与你的输出不同,说明了未定义行为的全部内容。~B ~A B :: operator delete~B ~A ~B ~A B :: operator delete[]
2赞 Peter 9/30/2023
@TobySpeight 如果大小与 相同,则也是未定义的行为。我认为这种情况更加危险,因为 - 尽管是未定义的行为 - 程序似乎可以工作(例如程序通过测试,不会崩溃等),直到某些事情发生变化(不同的编译器,安装在另一台机器上,最终用户运行程序而不是开发人员等)并且它意外停止工作。随着时间的流逝,这些潜伏的缺陷往往会导致恼火的最终用户(客户!)和沮丧的开发人员。BA

答: 暂无答案