Hi,
Ich beschäftige mich zur Zeit mit OGRE und OIS (eine recht gut passende input-bibliothek für OGRE). Das Problem ist, dass OIS z.B. beim drücken einer maustaste nur maximal eine "stelle" darüber informieren kann. Wenn man jetzt aber zwei verschiedene Objekte informieren will, braucht man eine Art Inputmanager, der als empfänger dient, und dann an alle anderen "stellen", die auch informiert werden wollen, eigenständig informiert.
Intern gelöst ist dieser Inputmanager (gefunden in einem OGRE-wiki-artikel) mit einer std::map. Man hat methoden wie addKeyListener(...), removeKeyListener(...) um "zuhörer" hinzuzufügen oder zu löschen. die methode keyPressed(...) wird bei einem echten tastendruck aufgerufen und sie selbst ruft wiederum dann die methode aller listener auf. Soweit so gut.
Hier vielleicht mal die keyPressed methode:
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
8
|
bool InputManager::keyPressed(const OIS::KeyEvent& evt) {
std::map<std::string, OIS::KeyListener*>::iterator itKeyListener = m_keyListeners.begin();
std::map<std::string, OIS::KeyListener*>::iterator itKeyListenerEnd = m_keyListeners.end();
for (; itKeyListener != itKeyListenerEnd; ++itKeyListener) {
if (!itKeyListener->second->keyPressed(e))
break;
}
}
|
Das Problem hierbei ist jetzt, dass während des iterierens über die map die keyPressed(e) methode der einzelnen zuhörer bestimmte zuhörer löschen oder hinzufügen kann. Dummerweise ist es relativ wahrscheinlich, dass sich der zuhörer selbst löscht. Konsequenz ist, dass der iterator der dann gerade auf das element zeigt, nicht mehr gültig ist und die schleife das programm zum abstürzen bringt.
Irgendwie fällt mir hier keine Lösung ein, wie ich über alle elemente iterieren kann, auch wenn währenddessen welche gelöscht werden können. Ein grund hierfür ist auch, dass die erase-methode der map keinen iterator auf das nächste element zurückliefert. Wieso nicht? Und wie kann ich das problem lösen?