I have an event bus that I'm using to publish events to subscribers. However, I'm finding that after I unsubscribe a subscriber successfully the publish method is already mid-delivery for the same event that just got delivered. It was my understanding that event polling was all on the same thread as the window, but I'm probably just not understanding it correctly. Here is some of my code:
EventBus.cpp
#include "engine/events/EventBus.hpp"
void EventBus::unsubscribe(EventSubscriber* eventSubscriber)
{
std::list<EventSubscriber*>::iterator iterator;
for (iterator = subscribers.begin(); iterator != subscribers.end(); ++iterator)
{
if (*iterator == eventSubscriber)
{
subscribers.erase(iterator);
break;
}
}
}
void EventBus::subscribe(EventSubscriber* eventSubscriber)
{
subscribers.push_back(eventSubscriber);
}
void EventBus::publish(Game* game, sf::Event e)
{
std::list<EventSubscriber*>::iterator iterator;
for (iterator = subscribers.begin(); iterator != subscribers.end(); iterator++) {
(*iterator)->deliver(game, e);
}
}
std::list<EventSubscriber*> EventBus::subscribers = {};
EventBus.cpp has all static members.
Button.cpp (partial)
void Button::deliver(Game* game, sf::Event e)
{
switch (e.type)
{
case sf::Event::MouseButtonReleased:
if (e.mouseButton.button == sf::Mouse::Left && m_text.getGlobalBounds().contains(sf::Mouse::getPosition(m_window).x, sf::Mouse::getPosition(m_window).y))
{
EventBus::unsubscribe(this);
game->newGame();
}
break;
case sf::Event::MouseMoved:
if (m_text.getGlobalBounds().contains(sf::Mouse::getPosition(m_window).x, sf::Mouse::getPosition(m_window).y))
{
if (handCursor)
{
SetCursor(handCursor);
}
}
else
{
if (arrowCursor)
{
SetCursor(arrowCursor);
}
}
break;
}
}
Before the new game is created I unsubscribe the "New Game" button, and then create the game. It does remove the button from the list of subscribers, but if I step out after that point it immediately jumps to this line in the publish method of EventBus.cpp:
(*iterator)->deliver(game, e);
The event it is delivering is the MouseButtonReleased, which was already delivered to the button, or else I wouldn't have been able to call unsubscribe. This throws the runtime exception "List iterator not incrementable". My event handling is pretty standard.
Game.cpp (partial)
void Game::handleEvents()
{
sf::Event event;
while (m_window.pollEvent(event))
{
EventBus::publish(this, event);
switch (event.type)
{
case sf::Event::Closed:
exit();
break;
case sf::Event::Resized:
// TODO: Resize view.
break;
case sf::Event::LostFocus:
pause();
break;
case sf::Event::GainedFocus:
pause();
break;
case sf::Event::KeyPressed:
if (event.key.code == sf::Keyboard::Escape)
{
exit();
}
else if (event.key.code == sf::Keyboard::P)
{
pause();
}
break;
default:
break;
}
}
}
That method is called in my main loop.
I'm drawing a blank on why this control flow would be incorrect, or what is wrong with my C++ code. Any help is appreciated. Thanks!
Brian