使用一个只会执行一次的while循环并使用break语句是不好的编程形式吗?

3
作为一个例子:
function()
{
    calculation1();

    while(1)
    {
        if (test1() == FAIL) { break; }

        calculation2();

        if (test2() == FAIL) { break; }

        calculation3();

        if (test3() == FAIL) { break; }

        calculation4();

        break;
    }

    final_calculation();

    return;
}

每个测试都依赖于之前所有计算得出的结果。如果一个测试失败,剩余的计算应该被跳过。
另一种方法是使用一系列嵌套的if()语句:
function()
{
    calculation1();

    if (test1() == SUCCESS)
    {
        calculation2();

        if (test2() == SUCCESS)
        {
            calculation3();

            if (test3() == SUCCESS)
            {
                    calculation4();
            }
        }
    }

    final_calculation();

    return;
}

然而,除了像上面这样高度抽象的示例外,在任何情况下采用后一种方法看起来都会变得非常混乱。我认为前一种方法在处理更长、更复杂的代码时更具可扩展性。是否有任何不选择第一种方法的原因呢?

使用无限循环存在着它将永远持续下去的风险!而使用条件语句则不会,它们只是判断真假,但代码会继续执行。 - Rizier123
这是一个观点问题,但我已经知道如何做了。不过,你应该始终检查是否可以更清晰地编写代码,而不使用“break”。 - The Archetypal Paul
1
我认为这样做还不错,但将它们放入一个函数中可能会更好。然后你可以使用return而不是break - Zan Lynx
7
我认为在适合使用“goto”的地方掩盖“goto”并不好。这是标准的C语言,没有异常处理的结构:当必须要用到这种代码时,“goto”是解决问题的一种方式(可以查看Linux内核源代码,你可能也会喜欢这篇文章:http://blog.regehr.org/archives/894)。 - Jubatian
@anatolyg:它几乎是,但那个问题混合了C和C ++。这两种语言提供了不同的可能解决方案,然而我看到的答案涵盖了C特定的东西(在那里我希望看到适当的异常处理演示,为什么它缺失了?虽然我对C ++知识很少...)。 - Jubatian
显示剩余3条评论
3个回答

5

我对这种技术没有问题,并经常使用它。

不过,通常我会将其格式化为:

    bool success = false;  // Pessimistically assume we will fail
    do
    {
        calculation1();
        if (test1() == FAIL)
        {
            break;
        }

        calculation2();
        if (test2() == FAIL)
        {
            break;
        }

        calculation3();
        if (test3() == FAIL)
        {
            break;
        }

        calculation4();
        success = true;  // Note the success!
    } while(false);

    // TODO: Check the success-variable to know if we failed early, or went all the way through.
    final_calculation();

    return;
}

有时我的同事不喜欢使用while(false)条件的循环。

3

goto语句就是goto语句。你应该直接使用它,而不是用while循环来隐藏它。

是的,在某些情况下,使用goto语句被认为是有害的,但在这种情况下,如果没有进行大规模的代码重构,就没有真正避免它的方法。

这才是真正的问题,也许修复它并不值得。


2
虽然在这种情况下我可能会暂时批准使用goto,但我有过同事看到一个goto后...认为goto是可以的,并添加了越来越多的goto,直到我们手头上出现了一个速龙爆发。因此,我总是避免使用goto。在这种情况下,do-while(false)break;完全可以胜任。我怀疑在汇编语言中,break语句与goto语句绝对相同,而且还有额外的安全性,即您永远不会意外地“向后中断”。但是,您可能会意外地向后跳转。 - abelenky

1
一个替代方案。
failed = false

if (!failed) {
   calculation1();
   if (test1() != SUCCESS)
      failed = true;
}
 if (!failed) {
   calculation2();
   if (test2() != SUCCESS)
      failed = true;
}
if (!failed) {
   calculation3();
   if (test3() != SUCCESS)
      failed = true;
}
if (!failed) {
   calculation4();
  }

执行最终计算();

(!在对称性上第一个检查失败)


这个方法非常明确,意义很大,但它的性能与原来的两个示例不同。 - yo.ian.g
确实如此,但是在测试和分配的成本产生任何明显差异之前,需要计算N非常微不足道。 - The Archetypal Paul
这段代码的结果与我的不同。函数final_calculation()不应该位于if()语句中,因为它应该始终被执行。请用calculation4()替换final_calculation(),并将final_calculation附加到代码末尾,那么就应该正确了。 - SharpHawk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接