c++ - 为什么删除操作符必须是静态的?

标签 c++ operator-overloading

我找到了 this one question asking the same thing ,但是只回答了"new"部分,所以又来了。

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

我知道,当调用删除操作符时,对象已经被销毁,所以不存在“this”。然而,使用与虚拟析构函数相同的推理,让删除运算符匹配创建对象的新运算符仍然是有意义的。

这就是我的意思

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

class B : public A
{
  public:
    void* operator new (size_t sz);
    void  operator delete (void* ptr, size_t sz);
};

现在如果我们这样做

A *ptr = new B();
delete ptr; // <-- fail

应该调用 A 的删除操作符(默认),因为它是静态的,并且在编译时不知道(除了这里的简单情况)哪个删除操作符是正确的。

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

我的(真正的)问题是:删除操作符是否存在某种隐含的“虚拟性”?它只是在没有这个指针的意义上是静态的吗?还是这只是一个 g++ 功能?

我开始查看 C++ 规范,但我必须承认,我对它有点不知所措,因此感谢任何帮助。

最佳答案

语言规则中的答案确实在 12.5 [class.free] 中。

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

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

原始分配和释放在概念上发生在对象的生命周期之外,因此在调用释放函数时,不再有对象提供虚拟查找机制,但查找规则确保 operator delete 具有动态(虚拟精简版!)查找机制。这意味着 operator delete 可以明智地是 static 而不会失去与原始对象的动态类型的联系。

关于c++ - 为什么删除操作符必须是静态的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2273187/

相关文章:

c++ - 运算符重载器没有影响

postgresql - 为 DISTINCT 调用创建 PostgreSQL 类型(点)的自定义 "equality operator"

C++ friend 运算符<<(ostream os, obj objName)

c++ - ARM Sprite -g++ : Command not found

c++ - 类型类似于泛型函数的模板成员变量

c++ - 具有一个特定函数的奇怪类型转换

C++是在每个实例化时创建的模板类中每个方法的新版本

c++ - move 语义和窗口句柄。 DeleteObject 安全句柄?

c++ - "SafeArray"指针的

c++ - 我已经完成了 << 运算符重载,但它不起作用