• Advertisement
Sign in to follow this  

Event Aggregator in C++ - Need Help

This topic is 878 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I was wanting to take a stab at creating an EventAggregator in c++.  It would work like so.  Each game object that wanted to be notified of specific game events would subscribe to the event using the event aggregator like so.

struct SomeSubscriber : Subscriber
{
	SomeSubscriber(std::shared_ptr<EventAggregator> ea)
	{
		ea->Subscribe(this, L"EnemySpotted");
	}

};

All Subscribers would derive from the following class

struct Subscriber
{
	virtual ~Subscriber()
	{
	}

	virtual void Handle(Event & e) = 0;
};

The Event Aggregator would look something like this

struct EventAggregator
{
	std::map<std::wstring, std::vector<std::weak_ptr<Subscriber>>> m_subscriptions;
	void Publish(Event & e);
	void Subscribe(std::weak_ptr<Subscriber> subscriber, std::wstring eventType);
};

The problem i have is i would like the gameobjects to subscribe to the event aggregator in their constructor but i'm not sure how to do this since the EventAggregator expects a shared_ptr<Subcriber>() in the Subscribe Method.  Does anyone have any advice/recommendations? 

Share this post


Link to post
Share on other sites
Advertisement

The problem i have is i would like the gameobjects to subscribe to the event aggregator in their constructor but i'm not sure how to do this since the EventAggregator expects a shared_ptr<Subcriber>() in the Subscribe Method.  Does anyone have any advice/recommendations? 

 

I don't believe this is possible, not while adhering to standards-compliant C++.  There are various ways to have an object's method's get a shared_ptr to itself, but for a variety of reasons, they're really not designed to be called from an object's own constructor.  There are a variety of pitfalls in trying to do that!

 

What about implementing a virtual init() function of sorts?  Construct your objects first, wrap them in a std::shared_ptr, then call their init() method.  Getting a std::shared_ptr to that method shouldn't be too-too hard.  For example, you could either:

 

- pass it in as a parameter, or

- utilize std::enable_shared_from_this, which allows a struct's/class's member functions to get std::shared_ptrs to itself, *but only if that object is already owned by at least one std::shared_ptr* (This is mandated by the C++ standard!)

 

 

Cheers, and best of luck!

-- David L.

Share this post


Link to post
Share on other sites

Why do you need a weak pointer?

 

Since the game objects derive from SubScriber, why not let Subcriber store the aggregators, and notify all of them of descruction in ~Subscriber ?

Share this post


Link to post
Share on other sites

Why do you need a weak pointer?

 

Since the game objects derive from SubScriber, why not let Subcriber store the aggregators, and notify all of them of descruction in ~Subscriber ?

I'm new to all the c++11 stuff but a weak_ptr to the subscriber is held by the event aggregator to prevent it from keeping an object alive when its no longer used.

 

as for letting the aggregator store the subscribers in not sure what this means

Share this post


Link to post
Share on other sites

 

The problem i have is i would like the gameobjects to subscribe to the event aggregator in their constructor but i'm not sure how to do this since the EventAggregator expects a shared_ptr<Subcriber>() in the Subscribe Method.  Does anyone have any advice/recommendations? 

 

I don't believe this is possible, not while adhering to standards-compliant C++.  There are various ways to have an object's method's get a shared_ptr to itself, but for a variety of reasons, they're really not designed to be called from an object's own constructor.  There are a variety of pitfalls in trying to do that!

 

What about implementing a virtual init() function of sorts?  Construct your objects first, wrap them in a std::shared_ptr, then call their init() method.  Getting a std::shared_ptr to that method shouldn't be too-too hard.  For example, you could either:

 

- pass it in as a parameter, or

- utilize std::enable_shared_from_this, which allows a struct's/class's member functions to get std::shared_ptrs to itself, *but only if that object is already owned by at least one std::shared_ptr* (This is mandated by the C++ standard!)

 

rCheers, and best of luck!

-- David L.

 

i could do that but it seems to be a bit of error prone. It's easy to forgot to call unit. This is why i was hoping to use the ctor. Any other ideas :)?

Share this post


Link to post
Share on other sites

as for letting the aggregator store the subscribers

I said it the other way around: "...why not let Subcriber store the aggregators..."

 

which leads to something like

struct Subscriber {
    Subscriber() { }
    virtual ~Subscriber() {
        for (auto agg : aggregators) agg->UnsubscribeAll(this);
    }

    void Subscribe(Aggregator &agg, std::string &evt_name) {
        agg.Subscribe(this, evt_name);
        aggregators.push_back(&agg); // EDIT: Messed up the shared ptr here :(
    }

    void HandleEvent(const Event &e) = 0;

    std::set<std::shared_ptr<Aggregator> > aggregators;
};

So the subscribed object knows which aggregators it uses, and unsubscribes all of them on destruction.

Edited by Alberth

Share this post


Link to post
Share on other sites

 

 

The problem i have is i would like the gameobjects to subscribe to the event aggregator in their constructor but i'm not sure how to do this since the EventAggregator expects a shared_ptr<Subcriber>() in the Subscribe Method.  Does anyone have any advice/recommendations? 

 

I don't believe this is possible, not while adhering to standards-compliant C++.  There are various ways to have an object's method's get a shared_ptr to itself, but for a variety of reasons, they're really not designed to be called from an object's own constructor.  There are a variety of pitfalls in trying to do that!

 

What about implementing a virtual init() function of sorts?  Construct your objects first, wrap them in a std::shared_ptr, then call their init() method.  Getting a std::shared_ptr to that method shouldn't be too-too hard.  For example, you could either:

 

- pass it in as a parameter, or

- utilize std::enable_shared_from_this, which allows a struct's/class's member functions to get std::shared_ptrs to itself, *but only if that object is already owned by at least one std::shared_ptr* (This is mandated by the C++ standard!)

 

rCheers, and best of luck!

-- David L.

 

i could do that but it seems to be a bit of error prone. It's easy to forgot to call unit. This is why i was hoping to use the ctor. Any other ideas smile.png?

 

What about creating a small function that would create an object, wrap it in a shared_ptr, then call init?  If you don't mind dabbing in templates a bit, it should be possible to write something like this:

std::shared_ptr<Thing> thing = make_thing<Thing>();

... whereby make_thing() operates almost identically to std::make_shared (and probably calls it, under the hood), but it calls Thing's init() method, after constructing it.

 

-- David L.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement