开发者

C++ event system design [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.

Want to improve this question? Update the question so it focuses on one problem only by editing this post.

Closed 4 years ago.

Improve this question

I need to use an event system in C++. I have mainly four requirements :

  1. Speed
  2. Ease of use
  3. Type Safety
  4. Friendly Destruction

By "Friendly Destruction" I mean the event and the subscriber need to manage their disconnection when one of them get destroyed :

  • An event shouldn't call a subscriber that has been destroyed.
  • A subscriber shouldn't be able to unregister from an event that has been destroyed.

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

User p开发者_运维问答oint 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 I used the fast delegates from this article http://www.codeproject.com/KB/cpp/FastDelegate.aspx.

The EventSubscriber class is needed for the "Friendly Destruction" aspect. (Otherwise I would have used a prettier design like in C#)

Any feedback is welcome.

Thanks.


Use boost::signals or boost::signals2 if you want thread safety.


Qt's signals and slots seem to fit your description nicely.


If you add smart pointers to this event system you should be in good shape. This example is very much like the C# event system, without many of the safeguards which could easily be implemented on top of the downloadable code. http://www.theorangeday.com/tutorials/c-event-system-using-delegates/

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜