Fak*_*ken 282 c++ for-loop break nested-loops
是否可以使用该break函数退出几个嵌套for循环?如果是这样,你会怎么做呢?你还可以控制休息退出的循环次数吗?
Hen*_*man 255
不,不要破坏它break.这是使用的最后一个据点goto.
小智 222
AFAIK,C++不支持命名循环,如Java和其他语言.您可以使用goto,或创建您使用的标志值.在每个循环结束时检查标志值.如果设置为true,那么您可以突破该迭代.
Pre*_*nik 56
只是使用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
}
}
}();
}
Run Code Online (Sandbox Code Playgroud)
当然这种模式有一定的局限性,显然只有C++ 11,但我认为它非常有用.
Gre*_*ill 55
打破嵌套循环的另一种方法是将两个循环分解为单独的函数,并return在要退出时从该函数中分解出来.
当然,这提出了另一个论点,即你是否应该return从最后的任何地方明确地使用函数.
Kar*_*and 32
break将仅退出包含它的最内层循环.
你可以使用goto来打破任何数量的循环.
当然goto通常被认为是有害的.
是否适合使用break函数[...]?
使用break和goto会使得更难以推断程序的正确性.看到这里讨论: Dijkstra并不疯狂.
sci*_*gor 22
虽然这件衣服已经出现了,但我认为一个好方法是做到以下几点:
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
jeb*_*det 19
这个怎么样?
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;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
Hel*_*tos 15
一个代码示例使用goto和一个标签来打破嵌套循环:
for (;;)
for (;;)
goto theEnd;
theEnd:
Run Code Online (Sandbox Code Playgroud)
Deq*_*ing 10
打破几个嵌套循环的一个好方法是将代码重构为函数:
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;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我不确定这是否值得,但是您可以使用一些简单的宏来模拟 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
Run Code Online (Sandbox Code Playgroud)
用法示例:
#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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
另一个例子:
#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);
}
Run Code Online (Sandbox Code Playgroud)
小智 5
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
Run Code Online (Sandbox Code Playgroud)
我知道这是一个旧线程,但我觉得这真的需要说并且没有其他地方可以说。对于这里的每个人,请使用goto。我刚用过。
就像几乎所有事情一样,goto 不是 100% 的“坏”或“好”。至少有两种用途,我要说的是,如果您为它们使用 goto - 并且不要将它用于其他任何用途 - 您不仅应该 100% 没问题,而且您的程序将比没有它更具可读性,因为它使您的意图更加清晰(有很多方法可以避免它,但我发现它们都更加笨拙):
不要只教条地接受“一般般是'邪恶'”这样的规则,而是要理解为什么要声称这种情绪,并遵循“为什么”,而不是情绪的字面意思。不知道这一点也给我带来了很多麻烦,以至于我会说教条地称事物为“邪恶”可能比事物本身更有害。最坏的情况是,你只会得到糟糕的代码——然后你知道你没有正确使用它,只要你听说过要小心,但如果你正在努力满足教条主义,我会说那更糟。
为什么“goto”被称为“evil”是因为你永远不应该用它来代替普通的 ifs、fors 和 whiles。为什么?试试看,一直尝试使用“goto”代替普通的控制逻辑语句,然后尝试用控制逻辑再次编写相同的代码,并告诉我哪个看起来更好更容易理解,哪个看起来更像一团糟. 你去吧。(奖励:现在尝试将新功能添加到 goto-only 代码中。)这就是为什么它是“邪恶的”,在“邪恶”周围有合适的范围限定。用它来短路C的" break"命令的缺点不是一个有问题的用法,只要你从代码中明确你的 goto 应该完成什么(例如使用像“nestedBreak”之类的标签)。打破嵌套循环是很自然的。
(或者更简单地说:使用 goto 跳出循环。我会说这更可取。不要使用 goto创建循环。那是“邪恶的”。)
你怎么知道你是否在教条?如果遵循“xyz 是邪恶的”规则导致您的代码不太容易理解,因为您正在扭曲自己试图绕过它(例如通过在每个循环中添加额外的条件,或一些标志变量,或其他类似的技巧) ,那么你很可能是教条的。
学习良好的思维习惯是无可替代的,比良好的编码习惯更重要。前者在后者之前,而后者通常会在前者被采用后随之而来。然而,问题是,我经常发现,后者没有得到足够的解释。太多简单地说“这是不好的”和“这需要更多的心思”不用说什么想,想什么约,以及为什么。这是一个很大的耻辱。
(FWIW,在 C++ 中,仍然需要打破嵌套循环,但不需要错误代码:在这种情况下,始终使用异常来处理错误代码,永远不要返回它们,除非它非常频繁以至于异常抛出和捕获将导致性能问题,例如在高需求服务器代码中的紧密循环中,也许[有些人可能会说“异常”应该“很少使用”,但这是深思熟虑的教条主义的另一部分:不,至少在我推翻那个教条之后的经验中,我发现它们使事情变得更加清晰——只是不要滥用它们做错误处理以外的事情,比如将它们用作控制流;实际上与“goto”相同。如果您将它们全部用于错误处理,这就是它们的用途。]。)