我有一个系统,它从某个地方(在这种情况下是网络)接收消息(带有类型的数据块)。一旦收到,它们就存储在队列中。然后这些消息应该被分派到处理程序函数,这很快就会发生(很多消息)
目前系统的设计方式是,每个Message类型都是一个自己的类,并覆盖虚拟函数run(Handler&),它基本上调用处理程序中的正确方法。 E.g:
class PingMessage: public Message{
... // Some member variables
void run(Handler& handler){
handler.handlePing(*this);
}
}
class Handler{
void handlePing(const PingMessage& msg){...}
}
在此设计中,队列在分派后删除该消息。问题是:某些处理函数需要存储消息以便以后执行它们。复制消息不仅浪费内存和时间(在调度后立即删除),有时也不可能(复杂的反序列化数据结构)所以最好将所有权传递给处理程序。
我有这种感觉,有一种设计模式或最佳实践。但我找不到它。
我可以成像的是调用泛型处理函数“handleMessage(Type,Message *)”,它打开类型并使用Message static_cast'ed到正确的类型进行调度。然后通过传递指针的惯例很清楚,处理程序负责删除消息。甚至可以使用基类,它执行切换并将所有处理函数实现为空。如果处理函数返回true,则handleMessage函数删除Message,否则它假定,被调用者将其存储在某处。但我不确定这是否是正确的方法,或者是否会产生很大的开销。似乎有很大的错误空间。
特别是因为我必须对消息类型进行2次检查:一种用于选择要反序列化的正确类,另一种用于调用正确的函数。
注意:没有C ++ 11可用。
旁注:还有其他一些东西:大多数处理程序只处理消息。所以在新的堆上创建它并在其之后释放它可能非常慢(大多数非常小的消息只有几个字节)使用处理程序,将消息反序列化为基于堆栈的对象会更好,但是我我必须再次复制它,我不能。那么我应该将原始消息传递给特定的处理函数并让它们按照自己的意愿进行反序列化吗?这意味着为不同的处理程序提供了大量重复的代码......这里做了什么???
答案 0 :(得分:1)
即使你表明你没有C ++ 11,也不需要很多代码来实现你自己的与C ++ 03兼容的std :: shared_ptr。如果您的应用程序不是多线程的,那么您甚至不必担心以线程安全的方式更新对象的引用计数。
我没有使用Boost,所以我不能权威地说,但是Boost可能已经有了一个与C ++ 03兼容的std :: shared_ptr实现,你可以使用
内存分配器的大多数现代实现实际上非常有效,并且在堆上实例化新的消息对象并不像你想象的那么大。
所以,你的整体方法是:
您收到消息,并在堆上实例化Message
的相应子类。
run()方法还应该接收消息本身的引用计数句柄,并将其传递给处理程序。
如果处理程序不需要保存消息的副本,它什么都不做,之后很快就会被销毁,否则会抓住引用句柄,并将其存放在某个地方。