问题描述
我有一个带有某种回调机制的状态机,这些函数是由任务运行程序调用的。所有这些的背后是一个状态机,它具有4种状态,有些状态彼此排斥,其他状态可以组合在一起,从而形成了相当复杂的规则集。如果试图进行任何非法操作,其中一个功能应显示用户错误消息(为简便起见,printf
在这里):
static int state1 = 0;
static bool switch2 = 1;
void do_stuff(int value){
int errorCode = 0;
if(state1 == 1){
errorCode = -1;
goto ERROR;
}
if(state1 == 2 && switch2)
{
errorCode = 2;
goto ERROR;
}
printf("No error!");
return;
ERROR:
printf("%d",errorCode);
}
这是我能想到的最短,最简洁的方法,但是它总是让人们意识到使用goto
是一件坏事。有没有更好的方法来解决此问题,或者就稳定性和维护而言,这是最好的方法吗?
解决方法
goto
是控制流的正确解决方案。尽管goto
有有效的用例,但在此特定功能中,您可以像下面这样简单地将控制流重构为if-else
分支:
void do_stuff(int value)
{
int errorCode = 0;
if (state1 == 1)
{
errorCode = -1;
}
else if (state1 == 2 && switch2)
{
errorCode = 2;
}
else // unconditional case for no errors
{
printf("No error!");
return;
}
printf("%s",errorCode); // if control reaches here,print the error
}
,
据我所知,您使用goto
进行错误处理,而不是用于状态机。
使用goto
进行错误处理实际上是那些情况非常有用且相对于复杂的条件链而言更受欢迎的情况之一。它使您无需重复代码即可执行手动RAII:
int do_stuff(...)
{
... = f1(...);
if (...)
goto ERROR_f1;
... = f2(...);
if (...)
goto ERROR_f2;
... = f3(...);
if (...)
goto ERROR_f3;
// Success
return ...;
ERROR_f3:
undo_f2(...);
ERROR_f2:
undo_f1(...);
ERROR_f1:
return ...;
}