views:

111

answers:

4

Here is my situation:

I have an event driven system, where all my handlers are derived from IHandler class, and implement an onEvent(const Event &event) method. Now, Event is a base class for all events and contains only the enumerated event type. All actual events are derived from it, including the EventKey event, which has 2 fields: (uchar) keyCode and (bool) isDown.

Here's the interesting part: I generate an EventKey event using the following syntax:

Event evt = EventKey(15, true);

and I ship it to the handlers:

EventDispatch::sendEvent(evt); // void EventDispatch::sendEvent(const Event &event);

(EventDispatch contains a linked list of IHandlers and calls their onEvent(const Event &event) method with the parameter containing the sent event.

Now the actual question:

Say I want my handlers to poll the events in a queue of type Event, how do I do that?

  • Dynamic pointers with reference counting sound like too big of a solution.

  • Making copies is more difficult than it sounds, since I'm only receiving a reference to a base type, therefore each time I would need to check the type of event, upcast to EventKey and then make a copy to store in a queue. Sounds like the only solution - but is unpleasant since I would need to know every single type of event and would have to check that for every event received - sounds like a bad plan.

  • I could allocate the events dynamically and then send around pointers to those events, enqueue them in the array if wanted - but other than having reference counting - how would I be able to keep track of that memory? Do you know any way to implement a very light reference counter that wouldn't interfere with the user?

What do you think would be a good solution to this design?

+1  A: 

Opinion: choose the reference counting option. Use boost::shareed_ptr, and boost::dynamic_pointer_cast to determine actual type.

Pavel Radzivilovsky
Thank you, I ended up implementing the smart pointer class (shared pointer) and it works like a charm! Great solution, thank you!
Kaa
Thx, though I really recommend you scrapping the NIH smart pointer in favor of boost::shared_ptr, which is also a part of the future C++ standard library (see TR1)
Pavel Radzivilovsky
+1  A: 

You don't really need reference counting unless you share your event objects. If you only have one owner at any given time - in your case, it would normally be the event queue - then you simply need to use an appropriate container.

If your implementation has partially implemented C++0x already (e.g. recent g++ versions, or VC++2010), then you can simply use std::queue<std::unique_ptr<Event>>. If std::unique_ptr is not available, you can use boost::ptr_deque or some other suitable container from the Boost Pointer Container library.

Pavel Minaev
+4  A: 

Ok, first off, this line doesn't do what you think it does:

Event evt = EventKey(15, true);

This creates a temporary EventKey object, slices it to the base class Event, then calls the Event copy constructor. All actual data kept in the EventKey class is lost. If you want polymorphism, you want to use either dynamic objects or references.

As for your actual question, I'd recommend you redesign and have separate queues (and thus separate handlers) for each event type... onEventA, onEventB, etc.

Terry Mahaffey
Thanks! I did my calls slightly different from this example, yet I did run into this problem! I for some reason thought I could cast objects :)
Kaa
A: 

NOTE: I am the OP, but did not have an account. Please treat this as an extension to the original question. My apologies for clogging up the thread.

Thank you for your responses. Object slicing explained to me that you can't cast objects the same way as pointers or references. But say I still have multiple handlers, each with their own event queues, and please assume the program is multi-threaded. By the way, I am running G++ (latest) on Linux (Ubuntu 10.04), IDE is Code::Blocks.

Assuming I changed the sendEvent and onEvent methods to hold a parameter of onEvent(const Event *pEvent) and I pass around pointers to dynamically allocated Events which are enqueued in separate containers, what would be the best way to handle ownership of that memory, and most importantly - what would be the most elegant way to handle the deallocation of that memory?

Another question on StackOverflow explained what a Shared Pointer is (also mentioned in one of the responses) - could someone please elaborate on what it is, and whether it would the needs of this specific case?

Thank you in advance, you are all incredibly helpful!

Kaa