Hello. I am trying to make something like an event or message system. There are Listeners, Messages and a Postman. The Listeners register themselves with the Postman to receive certain types of messages. You can send Messages through the Postman to all Listeners registered for that Message type.
The Postman keeps track of Listeners by mapping Message type to a std::set of Listeners. When a Message is posted, the receiveMessage function of all Listeners in the appropriate set will be called.
The problem is with unregistering. It is supposed to remove a Listener from all sets. And from checking size of the set before and after erase that seems to work. But for some reason, the next time a Message is posted, the unregistered Listener still receives the Message.
It is like I erase from a copy of the set or something? But I can't see the error.
Code:
#include <iostream>
#include <set>
#include <unordered_map>
class Message {
public:
enum Type { MESSAGE0, MESSAGE1, MESSAGE2, MESSAGE3 } type;
Message(Type t) : type(t) {}
};
class Listener {
public:
Listener(int id) : id(id) {}
void receiveMessage(Message m) {
std::cout << " Listener " << id << " received a message of type " << m.type << std::endl;
}
private:
int id;
};
class Postman {
public:
Postman() {
listeners = std::unordered_map<Message::Type, std::set<Listener*>, std::hash<int> >();
}
void postMessage(Message message) {
std::cout << "Someone is sending a message of type " << message.type << std::endl;
auto it = listeners.find(message.type);
if(listeners.end() != it) {
std::cout << "The set for message type " << message.type << " has size " << it->second.size() << "." << std::endl;
for(auto listener : it->second)
listener->receiveMessage(message);
}
}
void registerListener(Listener *l, Message::Type type)
{
auto it = listeners.find(type);
if(listeners.end() == it) {
std::pair<Message::Type, std::set<Listener*> > pair (type, std::set<Listener*>());
auto result = listeners.insert(pair);
if(result.second) {
it = result.first;
}
else {
std::cout << "Insertion failed." << std::endl;
return;
}
}
listeners.at(type).insert(l);
}
void unregisterListener(Listener *l) {
for(auto it : listeners) {
std::cout << "The set for message type " << it.first << " has size " << it.second.size() << "." << std::endl;
int i = it.second.erase(l);
std::cout << " I erased " << i << " elements from the set." << std::endl;
std::cout << " The set now has size " << it.second.size() << "." << std::endl;
}
}
private:
std::unordered_map<Message::Type, std::set<Listener*>, std::hash<int> > listeners;
};
int main(int argc, char** argv) {
auto pm = Postman();
auto l1 = Listener(1);
auto l2 = Listener(2);
pm.registerListener(&l1, Message::Type::MESSAGE1);
pm.registerListener(&l1, Message::Type::MESSAGE3);
pm.registerListener(&l2, Message::Type::MESSAGE2);
pm.registerListener(&l2, Message::Type::MESSAGE3);
std::cout << std::endl;
pm.postMessage(Message(Message::Type::MESSAGE1));
pm.postMessage(Message(Message::Type::MESSAGE2));
pm.postMessage(Message(Message::Type::MESSAGE3));
std::cout << std::endl;
pm.unregisterListener(&l1);
std::cout << std::endl;
pm.postMessage(Message(Message::Type::MESSAGE1));
pm.postMessage(Message(Message::Type::MESSAGE2));
pm.postMessage(Message(Message::Type::MESSAGE3));
}
In main I create two Listeners. One subscribes to type 1 and 3, the other to 2 and 3. Then I send a message of each type.
Then one of the Listeners unregisters and the same three messages are sent. The unregistered Listener still receives them, and the size of the sets have gone up again.
The exact output from the above program is
Code:
Someone is sending a message of type 1
The set for message type 1 has size 1.
Listener 1 received a message of type 1
Someone is sending a message of type 2
The set for message type 2 has size 1.
Listener 2 received a message of type 2
Someone is sending a message of type 3
The set for message type 3 has size 2.
Listener 2 received a message of type 3
Listener 1 received a message of type 3
The set for message type 2 has size 1.
I erased 0 elements from the set.
The set now has size 1.
The set for message type 3 has size 2.
I erased 1 elements from the set.
The set now has size 1.
The set for message type 1 has size 1.
I erased 1 elements from the set.
The set now has size 0.
Someone is sending a message of type 1
The set for message type 1 has size 1.
Listener 1 received a message of type 1
Someone is sending a message of type 2
The set for message type 2 has size 1.
Listener 2 received a message of type 2
Someone is sending a message of type 3
The set for message type 3 has size 2.
Listener 2 received a message of type 3
Listener 1 received a message of type 3
Any help would be appreciated.