1

这就是我正在做的事情:

#include <iostream>

using namespace std;

class Test
{
public:
    int i;
    Test();
    Test(int x);
    ~Test();

    static void operator delete(void * t);
};

Test::Test() : i(1) { cout << "constructing" << endl; }

Test::Test(int x) : i(x) { cout << "constructing w/ arg" << endl; }

Test::~Test() { cout << "destructing" << endl; }

Test::operator delete(void *self)
{
    cout << "deleting" << endl;
    ((Test *) t)->~Test(); // call destructor since it isnt called otherwise
    ::delete(t); // actually delete memory
}

template <typename T> // too lazy to figure out correct type
void callback(Test *t, T fn)
{
    (fn)(t); // delete operator is implicitly static so this syntax is correct
}

int main()
{
    Test *t = new Test();
    callback(t, &Test::operator delete); // deletes t
}

我注意到除非operator delete为我的类重载,否则前面的代码段将无法编译。如果包含它,它将按预期编译和工作(首先调用构造函数,然后重载删除,然后是析构函数,每个都恰好一次)。

我想过传递全局删除运算符::operator delete,但这也不起作用(我得到一个未解决的重载函数调用)。我可以调用它而无需尝试获取它的地址。

如果没有定义我自己的重载,我正在做的事情是否可能::operator delete

我知道基本上没有用例需要我使用这样的东西。我知道这::operator delete不是通用的东西,而且它不调用析构函数....

4

1 回答 1

4

全局运算符new/delete是重载函数 - 您需要转换为正确的函数指针类型:

callback(t, static_cast<void(*)(void*)>(::operator delete));

编辑:我正在扩大我的答案以澄清一些事情。

确实,全局不调用析构函数operator delete。它只是负责将内存返回到运行时的释放函数。调用析构函数是删除表达式的工作:

删除表达式首先调用其指针参数指向的对象(或对象,如果我们使用数组形式)的析构函数,然后调用释放函数(如果被删除的指针是类类型,它会在该范围内查找它)首先类,如果找不到,则调用全局类)。

另一个需要注意的重要事项是,void*在 delete 表达式中使用指针是未定义的行为,这就是您在重载中所做的:

cout << "deleting" << endl;
((Test *) self)->~Test();
::delete(self); // this is delete expression using void*, UB

你没有打电话给 global operator delete,因为你需要说::operator delete(t);。您有一个删除表达式,范围解析运算符只是告诉它不要在类范围内查找释放函数。

如果你把它改成这个,::delete( (Test*) self);你会看到destructing被打印两次,再次是 UB。

总而言之,不要在里面调用析构函数operator delete,这不是它的工作。

于 2013-07-09T21:50:48.093 回答