I have a system, that receives messages (data chunks with a type) from somewhere (in this case network). Those are stored in a queue once received. Then these messages should get dispatched to handler functions and this got to happen fast (lots of messages)
Currently the system is designed in a way, that each Message type is an own class and overwrites a virtual function run(Handler&) which basicly calls the correct method in the handler. E.g.:
class PingMessage: public Message{
... // Some member variables
void run(Handler& handler){
handler.handlePing(*this);
}
}
class Handler{
void handlePing(const PingMessage& msg){...}
}
In this design, the Queue deletes the message, after it got dispatched. The problem is: Some handler functions need to store the message to execute them at a later time. Copying the message is not only a waste of memory and time (it gets deleted right after dispatch) but also not possible sometimes (complex deserialized data structures) So best would be to pass the ownership over to the handler.
I have the feeling, there is a design pattern or best practice for this. But I can't find it.
What I could imaging is calling a generic handler function "handleMessage(Type, Message*)" that switches on the type and does a dispatch with the Message static_cast'ed to the right type. Then it is clear by the convention of passing a pointer, that the handler is responsible for deleting the message. Maybe even use a base class, that does the switch and implements all handler functions empty. If a handler functions returns true, the handleMessage function deletes the Message, otherwise it assumes, the callee stored it somewhere. But I'm not sure if this is the right approach or if it incurs to much overhead. There seems to be to much room for errors.
Especially as I would have to do 2 checks for the Message Type: One for choosing the correct class to deserialize and one for calling the correct function.
Note: No C++11 available.
Sidenote: There is also something else to it: Most handlers just handle the message. So creating it on the heap with new and freeing it right after that is propably quite slow (mostly very small messages with just a couple of bytes) Using a handler, that deserializes the messages into stack based objects would be better, but then I'd have to copy them again which I can't. So shall I pass the raw message to the specific handler function and let them do deserialization as they wish? That means lots of duplicate code for different handlers... What do to here???
Even though you indicate that you do not have C++11, it does not take a lot of code to implement your own C++03-compatible equivalent of std::shared_ptr. If your application is not multi-threaded, you won't even need to worry about updating the object's reference count in a thread-safe manner.
I don't use Boost, so I can't say authoritatively, but it's possible that Boost might already have a C++03-compatible implementation of std::shared_ptr that you can use.
Most modern implementations of memory allocators are actually quite efficient, and instantiating a new message object on the heap isn't as big deal as you think.
So, your overall approach is:
You receive the message, and instantiate the appropriate subclass of Message
on the heap.
The run() method should also receive a reference-counted handle to the message itself, which it passes to the handler.
If the handler does not need to save a copy of the message, it does nothing, and it will be destroyed soon thereafter, otherwise it grabs the reference handle, and stashes it away, someplace.