这是我在不存在 C++ 异常时使用的一些模式。在所有情况下,目的是在代码中有一个返回点。 (因为单点返回通常会使代码更具可读性和可维护性 - 并非总是如此,但努力争取是一件好事。)此外,当您利用 RAII 时,所有解决方案都很棒(让局部变量的析构函数为您完成所有清理工作)。
经典方法是“三角形模式”:
int MyCode()
{
int v1, v2, v3, v4;
int result = FAIL;
v1 = func1();
if (v1 == OK)
{
v2 = func2();
if (v2 == OK)
{
v3 = func3();
if (v3 == OK)
{
v4 = func4();
if (v4 == OK)
{
result = OK;
}
else
{
// handle func4 failure
}
}
else
{
// handle func3 failure
}
}
else
{
// handle func2 failure
}
else
{
// handle func1 failure
}
if (result != OK)
{
// general cleanup
}
}
对于上述情况,如果您可以利用 RAII 或将大部分“句柄清理代码”放在最后的 // general cleanup 块中,则不必在每个嵌套的 else 子句中编写冗余代码- 可能完全排除 else 子句。
另一个我喜欢使用的变体是“链式成功检查”:
int MyCode()
{
int result = OK;
result = func1();
if (result == OK)
{
// additional code to handle result of func1 before invoking func2
result = func2();
}
if (result == OK)
{
// additional code to handle result of func2 before invoking func3
result = func3();
}
else
{
// special error handling for func3 failing
}
if (result == OK)
{
result = func4();
}
if (result == OK)
{
// handle success case, if anything
}
else
{
// general error handling and function cleanup goes here
}
return result;
}
一开始看起来很奇怪,但是当您以上述风格编写代码时,它可以让您看到代码的预期流程(当成功是常态时)。您可能会观察到,当发生错误情况时,对result==OK 进行了大量冗余检查。在发布版本中,编译器可以对此进行优化。
链式成功检查的另一种变体是使用……等待它……不要惊慌……goto 宏专门用于跳转到函数的末尾(人群喘气)失败。但是看看它使代码看起来多么简单:
#define JUMP_ON_ERROR(expr) {result = (expr); if (result != OK) goto Cleanup;}
int MyCode()
{
int result = OK;
JUMP_ON_ERROR(func1());
JUMP_ON_ERROR(func2());
JUMP_ON_ERROR(func3());
JUMP_ON_ERROR(func4());
Cleanup:
if (result == OK)
{
// handle success
}
else
{
// handle failure
}
return result;
}