0

我正在使用以下公共方法研究有限状态机库:

template <typename STATE_T>
void add_state();              // allocate STATE_T on heap - STATE_T must derive from state

template <typename FROM_STATE_T, typename TO_STATE_T>
void link_state(std::function<bool()> cond, unsigned int priority);

// search for base state pointer that can be dynamically caste d to STATE_T* type, set this state as the beginning state
template <typename STATE_T>
void begin_state();

void execute();

//STATE_T must be a user defined state class that inherits from the base state class.

我选择了运行时实现而不是编译时,因为当对状态使用可变参数模板参数时,接口会更加复杂。但是,我想强制执行一些约束,以确保程序员在实现其状态机时不会引入错误。

以下是我要强制执行的约束:

  1. 不能添加重复状态(即添加两个相同的派生类型)
  2. 无法链接不存在的状态(例如不在 fsm 状态列表中的状态类型)
  3. 状态必须有一个入口点/可以到达
  4. 必须存在开始和结束状态
  5. execute 不能同时运行多次

断言中止程序并明确遵守这些约束,但它是正确的选择吗?

有可能违反 1,2,3 并且 fsm 仍然处于有效状态(只是什么都不做),但我不喜欢隐式处理这些的想法,因为它通过隐藏程序员错误引入了错误的安全感。

如果我为 1、2、3 抛出异常并且程序员捕获了它们,那么 fsm 仍可能处于有效状态,从而允许格式错误的 fsm 运行。

5是不应该做的事情。我应该处理这个,还是将其保留为 UB?

对于这些约束,最合适的机制是什么?

4

1 回答 1

2

这是处理错误的一个相当典型的问题。答案通常取决于成本。问题被忽视的代价是什么?程序因异常而中止的成本是多少?

在大多数情况下,程序崩溃的代价并没有那么大。用户只需重新启动它。在这种情况下,您应该选择未处理的异常。这样,您将快速发现错误,修复它们,并最终获得更好的程序。

有一种混合方法:在 DEBUG 构建中,使用“断言失败”消息框处理错误(通常使用 ASSERT() 宏完成),但在发布构建中,静默处理错误。然而,这会让问题在客户的计算机上被忽视,经常触发其他难以发现的错误。

最后,关于您担心程序员可以处理异常:这不是您应该考虑的事情。你指出了一个致命错误,如果程序员忽略它,那是他的错。

于 2013-08-21T12:13:27.707 回答