Я реализовал конечный автомат, который наследует boost :: statechart. Когда я звоню fsm.process_event( some_event() )
какая реакция выдает исключение, получается, что после того, как я обработаю исключение с помощью блока try-catch, мой экземпляр statemachine fsm
прекращено. То есть, fsm.terminated()
возвращается true
, В некоторых случаях я не хочу, чтобы это было прекращено. Например, когда я хочу, чтобы машина состояния выдавала исключение, чтобы сообщить вызывающему fsm.process_event( irrelevant_event() )
для необработанного события и для сохранения его текущего до состояния события.
Короче говоря — как я могу предотвратить boost::statechart
от завершения после того, как оно генерирует исключение и сохраняет его до состояния исключения?
Пример кода:
namespace sc = boost::statechart;
class State;
struct some_event : public sc::event<some_event> { };
class FSM
: public sc::state_machine< FSM, State, std::allocator<void>, sc::exception_translator<> >
{
public:
FSM()
{
cout<<"FSM::FSM()"<<endl;
}
virtual ~FSM()
{
cout<<"FSM::~FSM()"<<endl;
}
};class State : public sc::simple_state< State, FSM >
{
public:
State()
{
cout<<"State::State()"<<endl;
}
virtual ~State()
{
cout<<"State::~State()"<<endl;
}
typedef boost::mpl::list<
sc::custom_reaction< some_event >,
sc::custom_reaction< sc::exception_thrown >
> reactions;
sc::result react( const some_event & e)
{
cout<<"State::react( const some_event &)"<<endl;
throw std::exception();
return this->discard_event();
}
sc::result react( const sc::exception_thrown & e)
{
cout<<"State::react( const sc::exception_thrown &)"<<endl;
throw;
return this->discard_event();
}
};
int main()
{
FSM fsm;
fsm.initiate();
try
{
fsm.process_event(some_event());
}
catch(...)
{
cout<<"Exception caught"<<endl;
}if(fsm.terminated())
{
cout<<"fsm2 is TERMINATED"<<endl;
}
else
{
cout<<"fsm2 is RUNNING"<<endl;
}
return 0;
}
Вывод кода:
FSM::FSM()
State::State()
State::react( const some_event &)
State::react( const sc::exception_thrown &)
State::~State()
Exception caught
fsm2 is TERMINATED
Я хочу, чтобы это:
FSM::FSM()
State::State()
State::react( const some_event &)
State::react( const sc::exception_thrown &)
State::~State()
Exception caught
fsm2 is RUNNING
Вы должны предоставить пользовательский обработчик исключений для вашего конечного автомата. Смотрите документацию по бусту здесь: http://www.boost.org/doc/libs/1_55_0/libs/statechart/doc/tutorial.html#ExceptionHandling
Для конечного автомата невозможно узнать, находится ли он все еще в действительном состоянии, когда генерируется исключение, поэтому действие по умолчанию для дескриптора исключения — завершить sm. Ваш пользовательский обработчик может выполнить очистку / проверку, чтобы убедиться, что sm находится в действительном состоянии, и распространять информацию вверх в другом поместье.
Лично я никогда не видел веских причин распространять информацию из СМ в порядке исключения. Это может быть, по всей вероятности, потому, что я никогда не работал в вашей конкретной области, но тем не менее здесь мой разум:
Если событие не имеет значения, тогда проигнорируйте его или зарегистрируйте его, это же событие может иметь значение в другом состоянии, но не в текущем. Если событие недействительно, то есть никогда не может произойти или имеет неправильное состояние, то это либо:
Других решений пока нет …