C++自定义删除

假设我们有以下代码:

class MyType
{
    public: int x;
}

MyType* object = new MyType();
delete object;

是否可以在删除之前检查对象是否具有特定的 x 值?例如,如果 object.x 是奇数,则在调用 delete 后该对象不应从内存中释放。简而言之,为此类进行自定义删除,我们可以选择何时可以在操作员删除调用中释放对象。

回答

您试图解决的真正问题是什么?

首先,这个问答是对 C++ 中常见场景的一个很好的教训:

  • 允许你做某事的语言,但仅仅因为你可以并不意味着你应该。
  • 在尝试解决XY 问题时通常会遇到这些情况。

在这种特殊情况下,您可能会寻找完全不同的东西(X 问题),而不是尝试超载operator delete(解决 Y 问题,使 的客户感到困惑MyType),MyType如果和何时应删除(或不删除)它们,例如基于对象特征(例如数据成员的奇数)。有关最小示例,请参见例如@Ayxan Haqverdili 的回答。


理论上解决错误识别的 Y 问题

对于这种用例,永远不要这样做。

可以重载operator delete(以及operator delete[]),方法是将其定义为要重载的类的静态成员函数(按词法范围查找优先级)。正如评论中所指出的,虽然重载通常的释放函数是合法的,但尝试有条件地允许多次调用它不是:

struct MyType final {
  int x;
  static void operator delete(void *p) {
    if (static_cast<MyType *>(p)->x % 2 == 1) {
      ::operator delete(p);
    }
  }
};

int main() {
  MyType *object = new MyType{42};
  delete object; // Not DEALLOCATED.
                 // Underlying object DESTRUCTED, however.
                 // Extremely confusing.
  ++(object->x);
  delete object; // UB: destructor for underlying object called twice.
}

根据[expr.delete]/6 [强调我的]:

如果 delete-expression 的操作数的值不是空指针值并且所选的释放函数(见下文)不是销毁运算符 delete,则 delete-expression将调用对象对象的析构函数(如果有)被删除的数组元素。

作为第二次尝试(强调:永远不要走这条路),我们可以通过重载和滥用(C++20 中的新)特定于类的销毁释放函数来避免调用析构函数(仅有条件地调用它) :

#include <iostream>
#include <new>

struct MyType final {
  int x;
  static void operator delete(MyType *p, std::destroying_delete_t) {
    if (p->x % 2 == 1) {
      p->~MyType();
      ::operator delete(p);
    }
  }
  ~MyType() {
      std::cout << "ndtor";
  }
};

int main() {
  MyType *object = new MyType{42};
  delete object; // Neither deallocated nor underlying object destructed.
  ++(object->x);
  delete object; // Destructed and deallocated.
}

虽然这个程序格式良好,但它确实滥用了新的破坏性删除重载。Clang 确实会发出-Wmismatched-new-delete警告,这通常是对 UB 的提示,但这里可能不准确。

无论如何,这似乎是停止解决这个特定 Y 问题的徒劳之旅的好地方。

  • @TedLyngmo 在对象生命周期之后(即在调用析构函数之后)访问对象是 UB。因此,GCC 可能会忽略 `++`。
  • @TedLyngmo 析构函数被调用两次。在此处查看输出 https://gcc.godbolt.org/z/joT6odoW5
  • @AyxanHaqverdili 谢谢,我会尽快删除(没有双关语)或更新答案。
  • @dfrib 好节目!我不知道有这样的东西存在。强制性 [xkcd 参考](https://xkcd.com/356/)。

以上是C++自定义删除的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>