翻译《有关编程、重构及其他的终极问题?》——37.注意在do {…} while (…)中的continue
标签(空格分隔):翻译 技术 C/C++
作者:Andrey Karpov
翻译者:顾笑群 - Rafael Gu
最后更新:2018年09月06日
37.注意在do {…} while (…)中的continue
这次的代码摘自Haiku项目(BeOS的继承者)。代码中的错误被PVS-Studio分析器诊断为:V696 The ‘continue’ operator will terminate ‘do { … } while (FALSE)’ loop because the condition is always false(译者注:大意是说循环的判断条件为false所以continue会退出循环)。
do {
....
if (appType.InitCheck() == B_OK
&& appType.GetAppHint(&hintRef) == B_OK
&& appRef == hintRef)
{
appType.SetAppHint(NULL);
// try again
continue;
}
....
} while (false);
解释
这里continue在do-while循环中工作的方式,并不是很多程序员希望的那样,因为每当执行到continue时,总会检查循环条件是否满足,我将会用更多的细节来解释这点。假设某个程序员写下了下面的代码:
for (int i = 0; i < n; i++)
{
if (blabla(i))
continue;
foo();
}
或写成这样:
while (i < n)
{
if (blabla(i++))
continue;
foo();
}
从直觉上,很多程序员都能理解当执行到continue时,循环控制的判断条件 (i < n) 会被(重新)判断,下面一个循环只有在判断为true的时候才会执行。但让一个程序员写了下面的代码:
do
{
if (blabla(i++))
continue;
foo();
} while (i < n);
这时,直觉就错了,因为他们没有在continue的上面看到判断条件,这样就会让他们理所当然的认为continue会立刻出发下一个循环执行。但事实并非如此,continue还是一如既往触发对判断条件的检查(译者注:即使这个判断条件在continue的下面)。
如果对这种循环中continue的理解缺失是否会造成真的运行错误呢?看运气吧。然而,如果循环判断条件一定时false时,错误就必定发生,就好像开头那段代码一样:那个程序员原计划通过随后的迭代执行一些特定的操作。在注释中的“//try again”清楚的表明了他们的意图。但结果却时没有“again”了,因为判断条件一直是false,所以当执行continue时,循环就结束了。
换句话说,在do {…} while (false)中实用continue,这个continue就等价于break。
正确的代码
可以有很多不同的方式来矫正前述代码。比如,创建一个无穷循环,然后用continue去继续,用break去结束:
for (;;) {
....
if (appType.InitCheck() == B_OK
&& appType.GetAppHint(&hintRef) == B_OK
&& appRef == hintRef)
{
appType.SetAppHint(NULL);
// try again
continue;
}
....
break;
};
建议
即使你真的知道以上的问题,也请尽量避免在do {…} while (…)中使用continue。因为你很可能因为不小心而犯这个错误,或者你的同事因为错误理解了你的代码而进行了错误的修改。我永远不会停止说:好的程序员,不是那种炫耀很多不同编程语言技巧的,而是那种能写出清晰、易理解、甚至可以让一个新手都能看懂其代码的。