I have some classes:
struct Listenable{
virtual void removeListener(Listener * listener) = 0;
};
class Listener{
public: //that way example is simpler
unsigned myCode = 0;
Listenable * subject = 0;
Listener(unsigned myCode, Listenable * subject)
: myCode(myCode), subject(subject){}
void notify(unsigned value){
if(value == myCode){
a->removeListener(this);
}
}
};
class A : public Listenable{
public: //that way example is simpler
std::vector<Listener*> listeners;
void fun(unsigned value){
for(auto listener : listeners){
b->notify(value);
}
}
void removeListener(Listener * listener){
auto it = std::find(listeners.begin(), listeners.end(), listener);
if(it != listeners.end()){
listeners.erase(it);
}
}
};
and the code:
A a;
Listener * l1 = new Listener(5, a);
Listener * l2 = new Listener(7, a);
a.listeners.push_back(l1);
a.listeners.push_back(l2);
a.notify(3); //OK
a.notify(5); //error
I get the vector iterator not incrementable error in a.notify(5).
I know that it's because when I notify the l1 listener (inside of for loop of A::fun(5)), it decides to unsubscribe (call to A::removeListener).
But how to solve this? I want to iterate throw all the listeners and notify them about an event. I cannot assume if any of them (or how many of them) will want to remove itself from the list (it can happens as a reaction to event or somewhere else). I also cannot assume which circumstances will force specific Listener to call A::removeListener(this) and when.
I could change void notify(...) to bool notify(...) where return true would mean "please, remove me". But I cannot be sure that user won't call A::removeListener(this) from the class that inherit from Listener anyway.
Aucun commentaire:
Enregistrer un commentaire