Hi!
I'm often faced to the problem, that I want to create CallbackMessages that rely on the existence of an object. Now, it could happen, that this object is destroyed while the CallbackMessage is still waiting to be dispatched. When it finally is dispatched, the pointer to the target object is dangling.
That's why I eventually came up with this solution: A callback message that registers itself to its target class and gets invalidated when the target class is destroyed.
Maybe you find this usefull as well.
header:
class VoidableCallbackMessage; /** This is the base class for objects that can invalidate a VoidableCallbackMessage upon their destruction. */ class VoidableCallbackMessageTarget { public: VoidableCallbackMessageTarget() {}; ~VoidableCallbackMessageTarget(); void invalidateAllCallbacks(); void attachCallbackMessage(VoidableCallbackMessage* message); void removeCallbackMessage(VoidableCallbackMessage* message); private: ListenerList<VoidableCallbackMessage> callbacks; }; /** \brief A callback message for the message thread that can be invalidated. Often, a callback message relies on an object, which might be deleted before the callback message has been dispatched. This base class attaches itself to a target object and invalidates itself, when the object is destroyed. */ class VoidableCallbackMessage: public CallbackMessage { public: VoidableCallbackMessage(); virtual ~VoidableCallbackMessage(); virtual void handleCallback(VoidableCallbackMessageTarget* target_) = 0; void invalidate(); bool isValid() { return isvalid; } void removeFromTarget(); void postAttachedToTarget(VoidableCallbackMessageTarget* target_); virtual void messageCallback(); private: VoidableCallbackMessageTarget* target; bool isvalid; };
c file
VoidableCallbackMessageTarget::~VoidableCallbackMessageTarget() { invalidateAllCallbacks(); } void VoidableCallbackMessageTarget::invalidateAllCallbacks() { callbacks.call(&VoidableCallbackMessage::invalidate); } void VoidableCallbackMessageTarget::attachCallbackMessage(VoidableCallbackMessage* message) { if (!callbacks.contains(message)) callbacks.add(message); } void VoidableCallbackMessageTarget::removeCallbackMessage(VoidableCallbackMessage* message) { if (callbacks.contains(message)) callbacks.remove(message); } VoidableCallbackMessage::VoidableCallbackMessage() { target = nullptr; isvalid = true; } VoidableCallbackMessage::~VoidableCallbackMessage() { removeFromTarget(); } void VoidableCallbackMessage::removeFromTarget() { if (target != nullptr) { target->removeCallbackMessage(this); target = nullptr; } } void VoidableCallbackMessage::postAttachedToTarget(VoidableCallbackMessageTarget* target_) { removeFromTarget(); target = target_; target->attachCallbackMessage(this); post(); } void VoidableCallbackMessage::invalidate() { isvalid = false; target = nullptr; } void VoidableCallbackMessage::messageCallback() { if (!isvalid) { target = nullptr; return; } handleCallback(target); removeFromTarget(); }
I was actually pretty suprised to find no Juce class for this. Maybe I missed something?
Maybe this concept (or any other that does the same trick) can be added to juce?