我也在使用这种模式,对于那些想知道的人,这里有一个抽象的例子:
do // while(0) for break
{
state1 = 0;
if (cond1())
{
if (cond2())
break;
state1 = opA();
}
if (cond3() || state1 && state1->cond4())
break;
...
Triumph(state1, ...);
// often here: return
}
Failure(state1, ...);
我认为这在以下情况下有效:
- 你有一个很长的序列(比如说,>~六个条件)
- 条件很复杂,并且您使用/建立重要状态,因此您无法将元素隔离为函数
- 您处于对异常不友好的环境中,或者您的
break
-ing 代码路径实际上不是异常
你可以做些什么:
使警告静音。毕竟,这只是一个警告。而且我没有看到会被此警告捕获的“典型错误”(例如键入 0 而不是您的条件)。
[编辑] 现在,这很愚蠢。您收到警告的典型错误是例如while (a1!=a1)
而不是while (a1!=a2)
.[/edit]
分解成函数,将状态移动到一个类,
这会将上面的代码转换为:
struct Garbler
{
State1 state1;
bool Step1()
{
state1 = 0;
if (cond1())
{
if (cond2())
return false;
state1 = opA();
}
return true;
}
bool Step2()
{
return cond3() || state1 && state1->cond4();
}
..
void Run()
{
if (Step1() && Step2() && ... && Step23())
Triumph(state1, ...);
else
Failure(state1, ...);
}
}
这可以说是可读性较差,更糟糕的是您将序列分开,这可能会导致一个非常有问题的类(其中成员可能只能按特定顺序调用)。
Scopeguards
这可能允许将休息时间转换为更容易接受的早期回报:
state1 = 0;
ScopeGuard gFailure = MakeGuard(&Failure, ByRef(state1), ...);
if (cond1())
{
if (cond2())
return;
state1 = opA();
}
if (cond3() || state1 && state1->cond4())
return;
// everything went ok, we can dismiss the scopeguard
gFailure.Dismiss();
Triumph(state1, ...);
它们可以用 C++0x 更优雅地编写,保留流程,但解决方案也不是那么灵活,例如,当Failure()
不能轻松地将其隔离为单个函数时。