为什么delete运算符必须是静态的?

fal*_*tro 14 c++ operator-overloading

我发现这个问题同样问题,但是只有"新"部分得到了回答,所以这里再说一次.

为什么delete运算符必须是静态的?不知何故,它没有意义.新运算符非常有意义,就像构造函数不能虚拟一样,新运算符也不行.但是,析构函数可以(并且应该)在使用继承时是虚拟的,以便允许销毁正在使用的对象(通过多态)作为基类.

据我所知,当调用delete运算符时,该对象已被销毁,因此不存在"this".然而,使用与虚拟析构函数相同的推理仍然有意义的是让delete运算符与创建对象的new运算符匹配.

这就是我的意思

class A
{
  public:
    virtual ~A() {}
};

class B : public A
{
  public:
    void* operator new (size_t sz);
    void  operator delete (void* ptr, size_t sz);
};
Run Code Online (Sandbox Code Playgroud)

现在如果我们这样做

A *ptr = new B();
delete ptr; // <-- fail
Run Code Online (Sandbox Code Playgroud)

应该调用一个删除操作符(默认值),因为它是静态的,并且在编译时不知道(除了这里的小事),delete-operator是正确的.

但是,我用上面的代码做了一个小的测试程序(在new/delete操作符中只有malloc/free,在delete中只有print语句),并使用g ++编译它.非常意外地运行它会在B的删除操作符中产生输出.

我的(真正的)问题是:删除操作符是否有一些隐含的"虚拟"?在没有这个指针的意义上它只是静态的吗?或者这只是一个g ++功能?

我开始查看C++规范,但我必须承认,我有点不知所措,所以任何帮助都会受到赞赏.

CB *_*ley 17

语言规则中的答案实际上是12.5 [class.free].

如果要通过指向基类的指针进行删除,则析构函数必须是虚拟的,否则会得到未定义的行为.否则,实现必须确定要删除的对象的动态类型.

12.5/4表示当delete没有前缀时,通过在动态类型的虚拟析构函数的上下文中::查找来确定释放函数delete.这确保了类似虚拟的查找,即使operator delete它始终是static成员函数.

原始分配和释放在概念上发生在对象的生命周期之外,因此在调用释放函数时,不再有对象提供虚拟查找机制,但查找规则确保operator delete具有动态(virtual-lite!)查找机制.这意味着操作员删除可以明显地static与原始对象的动态类型失去联系.

  • 5.3.5以及3.7.3和12.5中也有相关内容.虽然被称为参考作品,但似乎你必须阅读它的封面,否则你永远不会知道是否有一个小段落与你在一个完全不同的部分中查找的东西有关看着. (3认同)