这就是我正在做的事情:
#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
不是一般用途,并且它不会调用析构函数....
答案 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
内调用析构函数,这不是它的工作。