Я экспериментирую с использованием конечного автомата в качестве модели для управления потоком простой игры. Войдите в главное меню, в котором вы выбираете, например, запуск игры или изменение параметров и т. Д.
Я делаю это путем создания базового класса State, от которого наследуется каждое состояние. У меня есть класс приложения, который управляет программным циклом, и добавить указатель на текущее состояние. Само приложение имеет метод changeState, который выходит из текущих состояний и вводит следующее. При входе в состояние я даю ему указатель на класс приложения, и каждое состояние содержит логику для переключения в следующее состояние.
Это вызывает ситуацию, когда я не уверен, что происходит, или, скорее, что должно произойти.
В частности: Программа опрашивает события. Событие передается в текущее состояние для обработки. Если ввод диктует переключение в следующее состояние, я вызываю функцию changeState. Функция изменения состояния удаляет текущее состояние и загружает следующее.
Моя путаница заключается в том, что если я удаляю состояние, из которого я вызвал функцию изменения состояния, что произойдет, когда я вернусь из функции изменения состояния? Немного упрощенного кода, чтобы показать, что я имею в виду более четко:
class Application
{
public:
void run();
void changeState( StateBase * nextState );
protected:
void Initialize(){m_running=false; changeState(new BaseState);};
private:
StateBase * m_currentState;
bool m_running;
};
void Application::run()
{
Initialize();
while (m_running)
{
Event event;
while ( pollEvent(event) ) // Process events until event queue is empty
{
m_currentState->handleEvent( event );
}
}
}
void Application::changeState( StateBase * nextState )
{
if (m_currentState!= 0)
{
m_currentState->exit();
delete m_currentState;
}
m_currentState = nextState;
m_currentState->enter( this );
}
class StateBase()
{
public:
void enter( Application * app ){ m_Application = app };
void handleEvent( Event const& event );
void exit(){};
private:
Application * m_Application;
}
void StateBase::handleEvent( Event const& event )
{
if ( event )
m_Application->changeState( new StateBase );
}
int main()
{
Application App;
App.run();
return 0;
}
Пытался поместить туда только важные биты. В любом случае, я вижу, что происходит: я запускаю приложение. Затем я вызываю открытый метод run (), который вызывает Initialize (), чтобы установить для переменной m_running значение true, и вызывает changeState для нового BaseState. changeState дает состояние указатель на это, так что событие может получить доступ к информации приложения.
Затем метод run опрашивает события и, обнаружив их, отправляет их в текущее состояние для обработки.
Если событие требует изменения состояния, оно вызывает m_Application-> changeState (new StateBase);
И вот тут я запутался. changeState () вызывает delete для m_currentState, который является экземпляром StateBase, выполняющим вызов. Когда управление возвращается из changeState (), оно переходит к событию, которое должно было быть удалено. Тем не менее, я проверил его, и он не падает. Конечно, я не пытался изменить ни одного из государств-членов.
В любом случае, я хотел бы знать, может ли кто-нибудь объяснить мне, что здесь происходит. Я все еще пытаюсь найти лучший способ справиться с этим, такой как использование синглетонов для Application и различных состояний, что избавило бы от необходимости использовать указатели вокруг и удалять состояния, когда я закончу с ними. Но именно этот узел привлек мое внимание.
Если вы не пытались что-либо делать с данным состоянием после перехода в следующее состояние — тогда ничего плохого не могло произойти. Короче говоря, это похоже на вызов функции delete из функции-члена — это разрешено, если это последнее, что происходит с объектом:
void Test::deleteMe(int c)
{
extern int b;
int a;
void f();
delete this;
// do not do this - do not touch/use this after delete
// this->a = 7;
// this->f();
// but you can use outer world and local variables
a = 7;
b = 8;
c = 9;
f();
return; // just returns from function after delete this.
}
В мире C, который проще для понимания (в отличие от мира C ++), эквивалент выглядит следующим образом:
Test* this;
....
void Test_deleteMe(Test* this)
{
free(this);
// this->a = 7; // do not do this
// f(this); // and this
return; // just returns from function after delete this.
}
Других решений пока нет …