Search code examples
c++wxwidgets

Using CallAfter to call wxWindow::Destroy generates compile-time error


I'm trying to destroy a wxWindow-derived object that is likely to have been subject to a Bind() from one of its container objects. Based on my reading (and some prior experience chasing weird errors), I believe I need to delay the call to Destroy() until after the event queue has been exhausted, otherwise there is a possibility that the event handler may attempt to access the destroyed object.

What I've been reading says to use CallAfter() to execute the object's Destroy() function. The problem is, if I call

obj->CallAfter(&ObjClass::Destroy);

I get a compile error "C2064 term does not evaluate to a function taking 0 arguments", pointing to the wxAsyncMethodCallEventFunctor::Execute() function in wx/event.h. This seems odd to me, given that wxWindow::Destroy() takes no arguments; I thought maybe the instance reference ("obj") was the problem, but when I tried to wedge it into the call other ways, I got errors saying I had too many parameters.

With some experimentation, I've been able to make it work by defining a function in my derived object that takes 0 arguments and (apparently critically) returns void rather than bool. It looks very much like:

void ObjClass::DestroyMe()
{
    this->Destroy();
}

Now, when I use the expression

obj->CallAfter(&ObjClass::DestroyMe);

the program compiles and appears to be working. Still, I hate this solution because it feels klunky.

  • Is there a better way to do this?

  • Am I correct in thinking the issue relates to the bool vs. void return values?

    • If so, can I somehow typecast the function reference to simulate a void() function call (since I don't care about the bool value)?

Solution

  • CallAfter() does expect a void callable because it would be dangerous if it took anything and then just discarded the result (because what else could it do with it?), so you can't pass it Destroy() directly.

    Your workaround is fine but, of course, in C++11 you can make it much shorter and more convenient by using lambdas which go very well with CallAfter(), so usually you'd just write

    obj->CallAfter([=]() { this->Destroy(); });