是否可以对全局运算符`new`和`delete`执行回调?

时间:2013-07-09 21:40:25

标签: c++ operator-overloading heap delete-operator

这就是我正在做的事情:

#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不是一般用途,并且它不会调用析构函数....

1 个答案:

答案 0 :(得分:4)

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

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

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

全局operator delete不会调用析构函数。它只是解除分配函数,负责将内存返回运行时。调用析构函数是delete expression

的工作

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

另一个需要注意的重要事项是在删除表达式中使用void*指针是未定义的行为,这是您在重载中执行的操作:

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

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

如果您将其更改为此::delete( (Test*) self);,您会看到destructing被打印两次,再次是UB。

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