You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 23:49:51