简体   繁体   中英

Is it possible to perform callbacks to the global operators `new` and `delete`?

Here's what I'm doing:

#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
}

I've noticed that unless operator delete is overloaded for my class, the previous snippet will fail to compile. If it's included, it will compile and work as expected (first the constructor is called, then overloaded delete, then the destructor, each exactly once).

I thought of passing the global delete operator ::operator delete , but that doesn't work either (I get an unresolved overloaded function call). I can call it without trying to get its address just fine.

Is what I'm doing even possible without defining my own overload of ::operator delete ?

I know that there is basically no use case where I'd ever need to use something like this. I know that ::operator delete is not a general use thing, and that it doesn't call destructors....

Global operator new/delete are overloaded functions - you'll need to cast to the correct function pointer type:

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

Edit: I'm expanding my answer to clarifiy some things.

It is true that the destructors are not called by the global operator delete . It's just deallocation function responsible to return the memory back to runtime. Calling destructors is the job of delete expression :

Delete expression first calls the destructors of the object (or objects, if we use array form) its pointer argument points to and then calls the deallocation function (if the pointer being deleted is of class type, it looks for it in the scope of that class first and calls the global one if it doesn't find it).

Another important thing to note is that using a void* pointer in delete expression is undefined behaviour, which is what you do in your overload:

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

You're not calling global operator delete , for that you'd need to say ::operator delete(t); . You have a delete expression and the scope resolution operator just tells it to not look inside class scope for deallocation function.

If you change it to this ::delete( (Test*) self); you'll see destructing being printed twice, again UB.

All in all, don't call the destructor inside operator delete , it's not its job.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM