一、传统 FSM 的'三宗罪'
几乎所有的 C/C++ 程序员都写过这样的状态机:
enum class RobotState { IDLE, CALIBRATING, MOVING, ERROR };
RobotState currentState = RobotState::IDLE;
// 潜在风险
void updateLogic() {
switch (currentState) {
case RobotState::IDLE: // do something...
break;
case RobotState::CALIBRATING: // do something...
break;
// 问题 1:假如这里漏写了 MOVING 的 case,编译器顶多给个警告,程序照跑不误!
case RobotState::ERROR: // do something...
break;
}
}
传统设计的致命伤:
- 静默失败:当你新增了一个状态(比如
HOMING),你必须在全工程搜索所有的switch并手动添加case。漏掉一个,就是隐藏的线上 Bug。 - 数据耦合(全局变量爆炸):处于
MOVING状态时,系统需要记录'目标坐标';处于ERROR状态时,系统需要记录'错误码'。在传统模式下,为了让所有状态都能访问这些数据,你不得不把它们全部定义为庞大的全局变量或类成员,导致极度浪费和耦合。 - 非法转换:没有任何机制能阻止你写出
if (error) currentState = RobotState::CALIBRATING;这种违背物理常理的代码。
二、设计思路:让状态成为'类型' (Type-Driven Design)
在现代 C++ (C++17 及以上) 的哲学中,状态不应该是一个枚举值,而应该是一个独立的'类型 (Class/Struct)'。
我们为每一个状态单独定义一个轻量级的结构体。更绝妙的是,只有在这个状态下才需要的数据,就包裹在这个状态自己的结构体里!
// 1. 定义独立的状态类型,自带专属数据!
struct IdleState {};
struct CalibratingState { int retry_count = 0; // 只有标定状态才需要记录重试次数 };
struct { target_x, target_y, target_z;
{ error_code; std::string error_message;

