I've been making a game state system and as it progressed I figured that each state will need to have access to the window everywhere within the state so I figured I'd make a reference to a window in my abstract state class. I also have a StateManager class which takes care of creating/adding/removing states and StateManager contains a reference to a window. State classes also contain a reference to a manager so they should be able to get the window easily from the manager which is passed to the constructor.
However when states are changing the program crashes upon reaching
while(window.pollEvent()) line.
Oddly enough this only happens if the State class contains a window reference as a member. If I instead have the window be a parameter for all the methods within then no crashes occur. I have no idea why that makes a difference.
Sadly the smallest possible example I could make which demonstrates this is around 94 lines long.
#include <iostream>
#include <vector>
#include <memory>
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <SFML/Window.hpp>
class Foo;
typedef std::unique_ptr<Foo> FooPtr;
class FooManager
{
private:
sf::RenderWindow& m_window;
std::vector< FooPtr > m_foos;
public:
FooManager(sf::RenderWindow& window) : m_window(window) {}
sf::RenderWindow& getWindow() { return m_window; }
void pushFoo( FooPtr );
void popFoo();
void changeFoo( FooPtr );
void doStuff();
};
class Foo
{
private:
FooManager& m_manager;
//By having the window reference here instead of as a parameter to doStuff() it causes crashes
//Removing the window reference from the class and having doStuff() take it as a parameter works just fine
sf::RenderWindow& m_window;
public:
Foo(FooManager& manager) : m_manager(manager), m_window(manager.getWindow()) {}
void doStuff()
{
sf::Event event;
//Upon pressing space the program breaks here at event poll
//Message: Unhandled exception at 0x5d693261 in Test.exe: 0xC0000005: Access violation reading location 0xfeeefefa.
while(m_window.pollEvent(event))
{
if(event.type == sf::Event::Closed) m_window.close();
else if( event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Space)
{
m_manager.changeFoo(FooPtr(new Foo(m_manager)));
}
}
m_window.clear(sf::Color::Black);
m_window.display();
}
};
void FooManager::pushFoo( FooPtr foo )
{
m_foos.push_back(std::move(foo));
}
void FooManager::popFoo()
{
if(!m_foos.empty())
{
m_foos.pop_back();
}
}
void FooManager::changeFoo( FooPtr foo)
{
if(!m_foos.empty())
{
m_foos.pop_back();
}
m_foos.push_back(std::move(foo));
}
void FooManager::doStuff()
{
if(!m_foos.empty())
{
m_foos.back()->doStuff();
}
}
int main()
{
sf::RenderWindow window(sf::VideoMode(400,400,32), "Test");
FooManager fm(window);
fm.changeFoo(FooPtr(new Foo(fm)));
while(window.isOpen())
{
fm.doStuff();
}
return 0;
}