禁用 goto 语句
9.7.3 ID_forbidGoto
历史表明,goto 语句会破坏程序的结构性规划,很容易导致逻辑混乱且不利于阅读和维护,在非自动生成的、对可读性有要求的代码中,建议禁用 goto 语句。
示例:
if (cond0) {
goto L; // Non-compliant
}
....
if (cond1) {
L:
....
}
语句的排列和作用域的嵌套描述了程序的静态结构,清晰的静态结构使人易于理解程序的行为,而 goto 语句会打破这种结构,无规律的跳转会严重地降低代码可读性,例中 goto L 会绕过第二个 if 语句的条件约束,可读性很差,应被禁止。
C 语言的流程管理较为简单,goto 语句可提供一定的灵活性,但不应作为常规实现手段,也应受一定的限制,在 C 代码中使用 goto 语句应遵循 ID_forbidGotoBlocks 和 ID_forbidGotoBack 等规则。
C++ 语言提供了更丰富的流程管理功能,在 C++ 代码中不应再使用 goto 语句。
下面给出 goto 语句的一种常用模式:
void foo(size_t n)
{
int *a = NULL, *b = NULL, *c = NULL;
a = (int*)malloc(n);
if (!a) {
goto E;
}
b = (int*)malloc(n);
if (!b) {
goto E;
}
c = (int*)malloc(n); // Multiple resource allocation
if (!c) {
goto E;
}
....
E: // Single exit point
free(a);
free(b);
free(c);
}
在多次资源分配过程中,如果某次分配失败则需要释放已分配的资源,利用 goto 语句可实现资源的统一释放,在 C 代码中如果不用 goto 语句反而会很繁琐,所以这种模式在 C 代码中可以复用。
由于 C++ 提供容器、智能指针等更丰富的资源管理手段,所以不建议在 C++ 代码中再使用这种模式,即使标准库没有和相关资源对应的功能,也应该利用“RAII”等机制对其先封装再使用。
void foo(size_t n) {
std::vector<int> a, b, c; // Safe and brief
....
}
相关
参考
C++ Core Guidelines ES.76
MISRA C 2012 15.1