C ++ Event System Design

I need to use a C ++ event system. I have basically four requirements:

  • Speed
  • Ease of use
  • Type Security
  • Friendly destruction

By "Friendly Destruction" I mean an event, and the subscriber needs to control the shutdown when one of them is destroyed:

  • An event should not call a subscriber that has been destroyed.
  • The subscriber should not be able to unregister from the destroyed event.

I wonder if anyone will have a nicer design than what I came up with:

User point of view:

struct ClickEventArg {};

//-------------------------------------------------------------------------
class Button
{
public:
    Event<ClickEventArg&> Clicked;

    void SendClick(ClickEventArg& arg)
    {
        Clicked(this, arg);
    }
};

//-------------------------------------------------------------------------
class User
{
public:
    void Register(Button* button)
    {
        button->Clicked.Subscribe(m_suscriber, this, &User::OnButtonClicked);
    }

    void OnButtonClicked(void* sender, ClickEventArg& arg)
    {
        std::cout << "button clicked";
    }

private:
    EventSubscriber m_suscriber;
};

//-------------------------------------------------------------------------
void Test()
{
    Button* button = new Button();
    User* user = new User();
    user->Register(button);
    button->SendClick(ClickEventArg());
    delete user;
    button->SendClick(ClickEventArg()); 
}

Internal Code:

class EventSubscriber;

//-------------------------------------------------------------------------
class BaseEvent
{
public:
    virtual void UnSubscribe(EventSubscriber& subscriber) = 0;
};

//-------------------------------------------------------------------------
template <class TEventArgs>
class Event : public BaseEvent 
{
public:
    ~Event()
    {
        UnSubscribeAll();
    }

    typedef fastdelegate::FastDelegate2<void*, TEventArgs> EventHandler;

    inline void operator() (void* sender, TEventArgs args) const 
    {
        for (SubscriberMap::const_iterator it = m_subscribers.begin(); it != m_subscribers.end(); ++it)
            it->second(sender, args);
    }

    template <class TClass, class TEventArgs>
    void Subscribe(EventSubscriber& subscriber, TClass* object, void (TClass::*methodAddress)(void* sender, TEventArgs e))
    {
        subscriber.Subscribe(this);
        m_subscribers[&subscriber] = fastdelegate::MakeDelegate(object, methodAddress);
    }

    void UnSubscribe(EventSubscriber& subscriber)
    {
        subscriber.UnSubscribe(this);
        m_subscribers.erase(&subscriber);
    }

    void UnSubscribeAll()
    {
        for (SubscriberMap::const_iterator it = m_subscribers.begin(); it != m_subscribers.end(); ++it)
            it->first->UnSubscribe(this);
        m_subscribers.clear();
    }

private:
    typedef std::map<EventSubscriber*, EventHandler> SubscriberMap;
    SubscriberMap m_subscribers;
};

//-------------------------------------------------------------------------
class EventSubscriber
{
    template <class TEventArgs> friend class Event;

public:
    ~EventSubscriber()
    {
        UnSubscribeAll();
    }

private:
    void Subscribe(BaseEvent* e)
    {
        m_subscriptions.insert(e);
    }

    void UnSubscribe(BaseEvent* e) 
    {
        m_subscriptions.erase(e);
    }

    void UnSubscribeAll()
    {
        EventSet copy(m_subscriptions);
        for (EventSet::iterator it = copy.begin(); it != copy.end(); ++it)
        {
            (*it)->UnSubscribe(*this);
        }
    }

    typedef std::set<BaseEvent*> EventSet;
    EventSet m_subscriptions;
};

You may notice that I used the quick delegates from this article http://www.codeproject.com/KB/cpp/FastDelegate.aspx .

EventSubscriber "Friendly Destruction". ( , #)

.

.

+3

Source: https://habr.com/ru/post/1773764/


All Articles