我该如何从循环中跳出来

How should I break out from a loop?

本文关键字:循环      更新时间:2023-10-16

每当我需要从C++中的for(unsigned int i=0;i<bound;++i)表达式中突破时,我只需设置索引变量i=bound,方法与本答案中描述的相同。我倾向于避免使用break语句,因为老实说,我不太了解它的实际作用。

比较两条指令:

for(unsigned int i=0;i<bound;++i) {
    if (I need a break) {
    break;
    }
}

for(unsigned int i=0;i<bound;++i) {
    if (I need a break) {
    i=bound;
    }
}

我推测,第二种方法在ibound之间做了一个额外的变量集,然后进行了一次额外的比较,因此从性能的角度来看,它看起来更加昂贵。那么问题是,调用break,然后进行这两个测试是否更便宜?编译后的二进制文件有什么不同吗?有没有第二种方法失败的例子,或者我可以安全地选择这两种方法中的任何一种?


Related:"break"是否仅适用于"for"、"while"、"do while"answers"switch';以及"if"语句?

在没有break语句的情况下中断循环[C]

使用break将更经得起未来的考验,也更符合逻辑。

考虑以下示例,

for (i = 0; i < NUM_OF_ELEMENTS; i++)
{
     if(data[i] == expected_item)
         break;
} 
printf("n Element %d is at index %dn", expected_item, i);

但第二种方法在这里没有用处。

  • 正如其他人所说,如果您的索引变量不局限于for作用域,break会保持其不变,而您的方法会破坏其内容;当你搜索一个带有break的数组时,代码会更简洁(你不必保留一个额外的变量来写下你停止的地方)
  • CCD_ 10立即退出循环;您的方法要求您执行正文的其余部分。当然,你总是可以写:

    for(int i=0; i<n; ++i) {
        if(...) {
            i=n;
        } else {
            rest of the loop body
        }
    }
    

    但它给你的循环增加了视觉和逻辑上的混乱;

  • break几乎肯定会被转换为简单的jmp,转换为循环后的指令(尽管,如果你有带析构函数的块范围变量,情况可能会更复杂);编译器不一定会将您的解决方案识别为等效解决方案。

    实际上,您可以在这里看到,gcc一直生成将n移动到i的代码,而在第二种情况下,它直接跳出循环。

在风格方面:

  • 我发现"你的方式"过于复杂且不地道——如果我在真实代码中遇到它,我会问自己"他为什么不使用break?"
  • 正如其他人所说,你的内部任务有与实际循环条件不同步的风险
  • 当循环条件变得比简单的范围检查更复杂时,无论是在逻辑方面(如果循环条件很复杂,那么欺骗它可能会变得更复杂)还是在性能方面(如果环路条件很昂贵,并且你已经知道你想退出,你不想再检查它),它都不会缩放;这也可以通过添加一个额外的变量来避免(通常在缺乏break的语言中这样做),但这又是对算法实际工作的额外干扰
  • 它根本不适用于基于范围的循环

我更喜欢break;,因为它保持循环变量不变
我经常在搜索时使用这个表格:

int i;
for(i=0; i<list.size(); ++i)
{
    if (list[i] == target) // I found what I'm looking for!
    {
        break;  // Stop searching by ending the loop.
    }
}
if (i == list.size() ) // I still haven't found what I'm looking for -U2
{
    // Not found.
}
else
{
    // Do work with list[i]. 
}

编译后的二进制文件不同吗
几乎可以肯定是的
(尽管优化器可能会识别您的模式,并将其简化为几乎相同)
break;语句可能是一个程序集"跳转"语句,用于跳转到列表外的下一条指令,同时保持控制变量不变。

分配变量(在未优化的代码中)将导致对控制变量的分配、对该变量的测试,然后产生结束循环的跳转。

正如其他人所提到的,如果循环条件在未来发生变化,那么将变量指定为其最终值就不那么经得起未来的考验。

一般来说,当您说:
"我不太了解它的实际作用。(所以我使用了一个变通方法)"

我回复:
"花点时间学习它的作用!作为程序员,你工作的一个主要方面是学习东西。"

使用break来做这件事是惯用的,应该是默认的,除非出于某种原因,相当模糊的替代方案为下面的逻辑设置了舞台。即便如此,我还是倾向于在循环退出后进行变量设置,为了清晰起见,将该设置移到更接近其用法的位置。

我无法想象这样一种情况:性能足够重要,以至于需要担心。也许一个更复杂的例子可以证明这一点。如前所述,这个问题的答案几乎总是"先量后调"。

除了break语句退出for或[do]while循环外,还允许使用goto来中断嵌套循环,例如:

    for (i=0; i<k; i++) {
        for (j=0; j<l; j++) {
            if (someCondition) {
                goto end_i;
            }
        }
    }
  end_i: