是否可以使用该break
函数退出多个嵌套for
循环?
如果是这样,你会怎么做呢?您还可以控制break
出口的循环次数吗?
不,不要用break
. 这是剩下的最后一个据点供使用goto
。
AFAIK,C++ 不支持命名循环,就像 Java 和其他语言一样。您可以使用 goto,或创建您使用的标志值。在每个循环结束时检查标志值。如果它设置为 true,那么您可以中断该迭代。
只是为了使用 lambdas 添加一个明确的答案:
for (int i = 0; i < n1; ++i) {
[&] {
for (int j = 0; j < n2; ++j) {
for (int k = 0; k < n3; ++k) {
return; // yay we're breaking out of 2 loops here
}
}
}();
}
当然,这种模式有一定的局限性,显然仅限于 C++11,但我认为它非常有用。
打破嵌套循环的另一种方法是将两个循环分解为一个单独的函数,并return
在您想要退出时从该函数中退出。
当然,这带来了另一个论点,即您是否应该return
在函数末尾以外的任何地方显式地访问该函数。
break将仅退出包含它的最内层循环。
您可以使用goto跳出任意数量的循环。
当然goto通常被认为是有害的。
使用中断功能[...]是否合适?
使用 break 和 goto 会使推理程序的正确性变得更加困难。有关此问题的讨论,请参见此处: Dijkstra 并不疯狂。
这个怎么样?
for(unsigned int i=0; i < 50; i++)
{
for(unsigned int j=0; j < 50; j++)
{
for(unsigned int k=0; k < 50; k++)
{
//Some statement
if (condition)
{
j=50;
k=50;
}
}
}
}
一个代码示例使用goto
和一个标签来打破嵌套循环:
for (;;)
for (;;)
goto theEnd;
theEnd:
尽管已经提出了这个答案,但我认为一个好的方法是执行以下操作:
for(unsigned int z = 0; z < z_max; z++)
{
bool gotoMainLoop = false;
for(unsigned int y = 0; y < y_max && !gotoMainLoop; y++)
{
for(unsigned int x = 0; x < x_max && !gotoMainLoop; x++)
{
//do your stuff
if(condition)
gotoMainLoop = true;
}
}
}
打破几个嵌套循环的一种好方法是将代码重构为一个函数:
void foo()
{
for(unsigned int i=0; i < 50; i++)
{
for(unsigned int j=0; j < 50; j++)
{
for(unsigned int k=0; k < 50; k++)
{
// If condition is true
return;
}
}
}
}
goto 对于打破嵌套循环非常有帮助
for (i = 0; i < 1000; i++) {
for (j = 0; j < 1000; j++) {
for (k = 0; k < 1000; k++) {
for (l = 0; l < 1000; l++){
....
if (condition)
goto break_me_here;
....
}
}
}
}
break_me_here:
// Statements to be executed after code breaks at if condition
我知道这是一个老话题,但我觉得这真的需要说,而且没有其他地方可以说。对于这里的每个人,请使用goto。我刚用过。
像几乎所有东西一样,goto 不是 100% 非此即彼/异或“坏”或“好”。我会说至少有两种用途,如果你对它们使用 goto - 并且不要将它用于其他任何东西 - 你不仅应该 100% 没问题,而且你的程序将比没有它更具可读性,因为它使您的意图更加清晰(有一些方法可以避免它,但我发现它们都更加笨拙):
不要只是教条地接受诸如“马马虎虎就是‘邪恶’”之类的规则,而是要理解为什么会声称这种情绪,并遵循“为什么”而不是情绪的文字。不知道这也给我带来了很多麻烦,以至于我会说教条地称事物为“邪恶”可能比事物本身更有害。在最坏的情况下,你只是得到了糟糕的代码——然后你知道你没有正确使用它,只要你听到要保持警惕,但如果你为了满足教条主义而苦恼自己,我会说那更糟。
为什么“goto”被称为“evil”是因为你不应该用它来代替普通的 ifs、fors 和 whiles。为什么会这样?试一试,一直尝试使用“goto”而不是普通的控制逻辑语句,然后尝试用控制逻辑再次编写相同的代码,并告诉我哪个看起来更好更容易理解,哪个看起来更乱. 你去吧。(奖励:现在尝试在 goto-only 代码中添加一个新功能。)这就是为什么它是“邪恶的”,在“邪恶”周围有合适的范围限定。用它来短路C的“ break
”命令的缺点是不行的一个有问题的用法,只要你从代码中明确你的 goto 应该完成什么(例如使用“nestedBreak”之类的标签或其他东西)。跳出嵌套循环是非常自然的。
(或者更简单地说:使用 goto 跳出循环。我会说这甚至更可取。不要使用 goto 来创建循环。那是“邪恶的”。)
你怎么知道你是不是教条主义的?如果遵循“xyz is evil”规则导致您的代码难以理解,因为您正在扭曲自己试图绕过它(例如通过在每个循环上添加额外的条件,或一些标志变量,或其他类似的技巧) ,那么你很可能是教条主义的。
学习良好的思维习惯是无可替代的,比良好的编码习惯更重要。前者先于后者,一旦采用前者,后者往往会紧随其后。然而,问题是,我经常发现后者没有得到足够的解释。太多的人只是说“这很糟糕”和“这需要更多思考”,而没有说明要思考什么、要思考什么以及为什么。这是一个很大的耻辱。
(FWIW,在 C++ 中,仍然需要跳出嵌套循环,但不需要错误代码:在这种情况下,始终使用异常来处理错误代码,永远不要返回它们,除非它过于频繁以至于异常抛出和捕获将导致性能问题,例如在高需求服务器代码中的紧密循环中,也许[有些人可能会说“异常”应该“很少使用”,但这是深思熟虑的教条主义的另一部分:不,至少根据我在推翻该教条后的经验,我发现它们使事情变得更加清晰——只是不要滥用它们来做除错误处理之外的其他事情,比如将它们用作控制流;实际上与“goto”相同。如果您将它们全部用于错误处理,这就是它们的用途。]。)
该
break
语句终止它出现的最近的封闭do
,for
,switch
, or语句的执行。while
控制权传递给终止语句之后的语句。
来自msdn。
我确实认为 agoto
在这种情况下是有效的:
要模拟break
/ continue
,您需要:
for ( ; ; ) {
for ( ; ; ) {
/*Code here*/
if (condition) {
goto theEnd;
}
}
}
theEnd:
for ( ; ; ) {
for ( ; ; ) {
/*Code here*/
if (condition) {
i++;
goto multiCont;
}
}
multiCont:
}
我不确定这是否值得,但您可以使用一些简单的宏来模拟 Java 的命名循环:
#define LOOP_NAME(name) \
if ([[maybe_unused]] constexpr bool _namedloop_InvalidBreakOrContinue = false) \
{ \
[[maybe_unused]] CAT(_namedloop_break_,name): break; \
[[maybe_unused]] CAT(_namedloop_continue_,name): continue; \
} \
else
#define BREAK(name) goto CAT(_namedloop_break_,name)
#define CONTINUE(name) goto CAT(_namedloop_continue_,name)
#define CAT(x,y) CAT_(x,y)
#define CAT_(x,y) x##y
示例用法:
#include <iostream>
int main()
{
// Prints:
// 0 0
// 0 1
// 0 2
// 1 0
// 1 1
for (int i = 0; i < 3; i++) LOOP_NAME(foo)
{
for (int j = 0; j < 3; j++)
{
std::cout << i << ' ' << j << '\n';
if (i == 1 && j == 1)
BREAK(foo);
}
}
}
另一个例子:
#include <iostream>
int main()
{
// Prints:
// 0
// 1
// 0
// 1
// 0
// 1
int count = 3;
do LOOP_NAME(foo)
{
for (int j = 0; j < 3; j++)
{
std::cout << ' ' << j << '\n';
if (j == 1)
CONTINUE(foo);
}
}
while(count-- > 1);
}
只需一个变量即可打破任意数量的循环,bool
请参见下文:
bool check = true;
for (unsigned int i = 0; i < 50; i++)
{
for (unsigned int j = 0; j < 50; j++)
{
for (unsigned int k = 0; k < 50; k++)
{
//Some statement
if (condition)
{
check = false;
break;
}
}
if (!check)
{
break;
}
}
if (!check)
{
break;
}
}
在这段代码中,我们break;
所有的循环。
其他语言如 PHP 接受 break 参数(即 break 2;)来指定要中断的嵌套循环级别的数量,但 C++ 不接受。您必须通过使用在循环之前设置为 false 的布尔值来解决这个问题,如果要中断,则在循环中设置为 true,在嵌套循环之后加上条件中断,检查布尔值是否设置为 true如果是,则打破。
我知道这是旧帖子。但我会建议一个合乎逻辑且更简单的答案。
for(unsigned int i=0; i < 50; i++)
{
for(unsigned int j=0; j < conditionj; j++)
{
for(unsigned int k=0; k< conditionk ; k++)
{
// If condition is true
j= conditionj;
break;
}
}
}
while (i<n) {
bool shouldBreakOuter = false;
for (int j=i + 1; j<n; ++j) {
if (someCondition) {
shouldBreakOuter = true;
}
}
if (shouldBreakOuter == true)
break;
}
您可以使用 try...catch。
try {
for(int i=0; i<10; ++i) {
for(int j=0; j<10; ++j) {
if(i*j == 42)
throw 0; // this is something like "break 2"
}
}
}
catch(int e) {} // just do nothing
// just continue with other code
如果你必须一次跳出几个循环,无论如何它通常是一个例外。
跳出 for 循环对我来说有点奇怪,因为 for 循环的语义通常表明它将执行指定的次数。但是,在所有情况下都不错。如果您正在搜索集合中的某些内容并希望在找到它后打破它,那么它很有用。然而,在 C++ 中不可能跳出嵌套循环。它在其他语言中是通过使用带标签的中断来实现的。您可以使用标签和 goto,但这可能会让您在晚上胃灼热..?似乎是最好的选择。