add DeferCall to replace QMetaObject::invokeMethod#48101
Conversation
| Call c = deferredCalls_.front(); | ||
| deferredCalls_.pop_front(); |
There was a problem hiding this comment.
This will execute a list of deferred calls in First-In-First-Out order, which seems to make sense to me. But defer in go executes in reverse order. I can't recall the specifics of any other languages right now, but I wonder if there's an expectation for one or other that might cause problems in the future, especially when using the deleteLater feature with complex data structures.
There was a problem hiding this comment.
Great point regarding deleteLater. Will double-check Qt's behavior before landing this, since the goal is for it to work similarly.
There was a problem hiding this comment.
Confirmed the deletions are in-order.
There is one exception: if there are nested event loops, deferred deletions only occur within the event loop that they were originally queued. So processing of deletions within an event loop is FIFO, but processing of the loops themselves is LIFO. In any case, we don't use nested event loops.
This helps reduce direct dependence on
QObjectby wrappingQMetaObject::invokeMethodwith our own internal API for doing the same. It introduces theDeferCalltype and updates a few places to use it. The goal is to useDeferCallfor all delayed invocations in the entire project, such that the only direct usage ofinvokeMethodoccurs withinDeferCallitself. Then when we replace the Qt event loop we can substitute out that final usage.Unlike
invokeMethod, which takes a method name by string and a variable number of dynamically typed args,DeferCall::defersimply takes a function/closure. This allows static type-checking, and any data that would have normally been supplied by args can be captured instead.A single
DeferCallinstance can be used to queue multiple calls. Destroying it will cancel the calls. Objects that need to make deferred calls to themselves are expected to do it through aDeferCallkept as a member variable. That way, when the object is destroyed so are its queued calls.DeferCallalso provides a replacement forQObject::deleteLater, via the static methodDeferCall::deleteLater. Deferred deletions are often applied to child objects during parent object destruction, so it is important for the queued calls to remain in effect after the parent object goes away. To help with that, these calls are made against a singleton (thread local) instead of a member instance.DeferCall::cleanupis used to destroy the singleton at thread/program exit.Tested with valgrind and came up clean.