Boost Statechart状态构造函数中发送事件触发断言失败
问题描述
使用Boost Statechart创建包含InitState、ProcessingState和ExitState三个状态的状态机,期望通过自定义事件依次完成状态过渡,但运行时触发断言失败。
代码实现
#include <boost/statechart/event.hpp> #include <boost/statechart/state_machine.hpp> #include <boost/statechart/simple_state.hpp> #include <boost/statechart/transition.hpp> #include <boost/statechart/custom_reaction.hpp> #include <boost/mpl/list.hpp> #include <iostream> namespace state_machine_example { namespace sc = boost::statechart; struct InitState; struct ProcessingState; struct ExitState; struct StartProcessing : sc::event<StartProcessing> {}; struct EndProcessing : sc::event<EndProcessing> {}; struct StateMachine : sc::state_machine<StateMachine, InitState> {}; struct InitState : sc::simple_state<InitState, StateMachine> { typedef sc::custom_reaction<StartProcessing> reactions; InitState() { std::cout << "Entering Init State\n"; this->post_event(StartProcessing()); } ~InitState() { std::cout << "Exiting Init State\n"; } sc::result react(const StartProcessing &event) { std::cout << "Transitioning from Init to Processing State\n"; return transit<ProcessingState>(); } }; struct ProcessingState : sc::simple_state<ProcessingState, StateMachine> { typedef sc::custom_reaction<EndProcessing> reactions; ProcessingState() { std::cout << "Entering Processing State\n"; this->post_event(EndProcessing()); } ~ProcessingState() { std::cout << "Exiting Processing State\n"; } sc::result react(const EndProcessing &event) { std::cout << "Transitioning from Processing to Exit State\n"; return transit<ExitState>(); } }; struct ExitState : sc::simple_state<ExitState, StateMachine> { ExitState() { std::cout << "Entering Exit State\n"; } ~ExitState() { std::cout << "Exiting Exit State\n"; } }; } // namespace state_machine_example int main() { state_machine_example::StateMachine state_machine; state_machine.initiate(); return 0; }
终端输出
Entering Init State state_machine_main: /usr/include/boost/statechart/simple_state.hpp:459: boost::statechart::simple_state<MostDerived, Context, InnerInitial, historyMode>::outermost_context_base_type& boost::statechart::simple_state<MostDerived, Context, InnerInitial, historyMode>::outermost_context_base() [with MostDerived = state_machine_example::InitState; Context = state_machine_example::StateMachine; InnerInitial = boost::mpl::list<mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>; boost::statechart::history_mode historyMode = boost::statechart::has_no_history; boost::statechart::simple_state<MostDerived, Context, InnerInitial, historyMode>::outermost_context_base_type = boost::statechart::state_machine<state_machine_example::StateMachine, state_machine_example::InitState>]: Assertion `get_pointer( pContext_ ) != 0' failed.
额外信息
- Boost版本:1.74.0
- 操作系统:Ubuntu 22.04
原因分析
断言失败的核心原因是在状态构造函数中调用post_event()时,状态的上下文指针pContext_尚未完成初始化。Boost Statechart的状态对象构造流程中,simple_state的上下文指针是在构造函数执行完毕后,由状态机框架完成赋值的。此时调用post_event()会尝试访问未初始化的pContext_,触发get_pointer(pContext_) != 0的断言。
另外,ExitState作为状态机的终止状态,当前代码中没有定义任何事件反应或终止逻辑,状态机进入ExitState后无法正常结束,也会导致后续潜在问题。
修复方案
1. 延迟事件发送:使用entry()替代构造函数发送事件
Boost Statechart提供了entry()方法,该方法会在状态构造完成、上下文指针初始化完毕后被调用,适合在此时发送事件。修改状态类,添加entry()方法:
struct InitState : sc::simple_state<InitState, StateMachine> { typedef sc::custom_reaction<StartProcessing> reactions; InitState() { std::cout << "Entering Init State\n"; } ~InitState() { std::cout << "Exiting Init State\n"; } void entry() { this->post_event(StartProcessing()); } sc::result react(const StartProcessing &event) { std::cout << "Transitioning from Init to Processing State\n"; return transit<ProcessingState>(); } }; struct ProcessingState : sc::simple_state<ProcessingState, StateMachine> { typedef sc::custom_reaction<EndProcessing> reactions; ProcessingState() { std::cout << "Entering Processing State\n"; } ~ProcessingState() { std::cout << "Exiting Processing State\n"; } void entry() { this->post_event(EndProcessing()); } sc::result react(const EndProcessing &event) { std::cout << "Transitioning from Processing to Exit State\n"; return transit<ExitState>(); } };
2. 完善ExitState的终止逻辑
在ExitState的entry()方法中调用terminate(),通知状态机结束运行:
struct ExitState : sc::simple_state<ExitState, StateMachine> { ExitState() { std::cout << "Entering Exit State\n"; } ~ExitState() { std::cout << "Exiting Exit State\n"; } void entry() { this->outermost_context().terminate(); } };
3. (可选)在main()中处理状态机事件循环
状态机初始化后,需要处理事件队列中的事件,添加事件循环逻辑:
int main() { state_machine_example::StateMachine state_machine; state_machine.initiate(); while (!state_machine.terminated()) { state_machine.process_event_queue(); } return 0; }
关于状态构造函数中发送事件的说明
不建议在状态构造函数中发送事件,原因如下:
- 状态构造时,上下文指针未完成初始化,调用
post_event()会触发未定义行为或断言失败; - 构造函数执行期间,状态尚未完全加入状态机的状态树,此时发送事件可能导致状态机处于不一致状态;
- 使用
entry()方法是Boost Statechart推荐的状态进入后执行逻辑的方式,能保证状态已完全初始化,上下文可用。
内容的提问来源于stack exchange,提问作者Schteve
相关产品推荐
相关产品推荐

