Est-il possible d'utiliser la break
fonction pour quitter plusieurs for
boucles imbriquées ?
Si oui, comment feriez-vous cela? Pouvez-vous également contrôler le nombre de boucles des break
sorties?
Est-il possible d'utiliser la break
fonction pour quitter plusieurs for
boucles imbriquées ?
Si oui, comment feriez-vous cela? Pouvez-vous également contrôler le nombre de boucles des break
sorties?
Réponses:
AFAIK, C ++ ne prend pas en charge les boucles de dénomination, comme Java et d'autres langages. Vous pouvez utiliser un goto ou créer une valeur d'indicateur que vous utilisez. À la fin de chaque boucle, vérifiez la valeur du drapeau. S'il est défini sur true, vous pouvez sortir de cette itération.
goto
si c'est la meilleure option.
goto
: les mauvais programmeurs et les programmeurs pragmatiques. Les premiers sont explicites. Ce dernier, dans lequel vous vous situeriez si vous choisissez de bien les utiliser, utilise un concept dit "maléfique" lorsqu'il s'agit du moindre de (deux) maux. Lisez ceci pour une meilleure compréhension de certains concepts C ++ que vous devrez peut-être utiliser de temps en temps (macros, goto, préprocesseur, tableaux): parashift.com/c++-faq-lite/big-picture.html#faq-6.15
goto
rarement la meilleure option. Pourquoi ne pas mettre les boucles dans leur propre fonction ( inline
, si vous êtes préoccupé par la vitesse) et à return
partir de là?
Non, ne le gâte pas avec un break
. Il s'agit du dernier bastion restant à l'usage de goto
.
Juste pour ajouter une réponse explicite en utilisant 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
}
}
}();
}
Bien sûr, ce modèle a certaines limites et évidemment C ++ 11 uniquement, mais je pense qu'il est très utile.
Une autre approche pour sortir d'une boucle imbriquée consiste à factoriser les deux boucles dans une fonction distincte et à return
partir de cette fonction lorsque vous souhaitez quitter.
Bien sûr, cela soulève l'autre argument de savoir si vous devez jamais explicitement à return
partir d'une fonction ailleurs qu'à la fin.
continue_processing
) qui contrôlaient l'exécution de blocs de code plus bas dans la fonction.
Pause ne quittera que la boucle la plus intérieure qui le contient.
Vous pouvez utiliser goto pour sortir de n'importe quel nombre de boucles.
Bien sûr, goto est souvent considéré comme nuisible .
est-il approprié d'utiliser la fonction break [...]?
L'utilisation de break and goto peut rendre plus difficile de raisonner sur l'exactitude d'un programme. Voir ici pour une discussion à ce sujet: Dijkstra n'était pas fou .
break
ou return
.
break
et vous return
avez l'avantage de goto
ne pas avoir à chercher une étiquette pour trouver où ils vont. Oui, en dessous, ils sont en quelque sorte goto
, mais très restreints. Ils sont beaucoup plus faciles à déchiffrer par le cerveau d'appariement de motifs d'un programmeur que par le libre goto
. Donc, l'OMI, ils sont préférables.
goto
.
Bien que cette réponse ait déjà été présentée, je pense qu'une bonne approche consiste à procéder comme suit:
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;
}
}
}
gotoMainLoop
est vérifié à chaque cycle
goto
rend le noyau plus lisible et plus performant.
Que dis-tu de ça?
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;
}
}
}
}
Un exemple de code utilisant goto
et une étiquette pour sortir d'une boucle imbriquée:
for (;;)
for (;;)
goto theEnd;
theEnd:
Une bonne façon de sortir de plusieurs boucles imbriquées est de refactoriser votre code en fonction:
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 peut être très utile pour casser des boucles imbriquées
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
Je pense qu'un goto
est valable dans cette circonstance:
Pour simuler un break
/ continue
, vous souhaitez:
for ( ; ; ) {
for ( ; ; ) {
/*Code here*/
if (condition) {
goto theEnd;
}
}
}
theEnd:
for ( ; ; ) {
for ( ; ; ) {
/*Code here*/
if (condition) {
i++;
goto multiCont;
}
}
multiCont:
}
i
. D'où i++
avant le goto
D'autres langages tels que PHP acceptent un paramètre pour break (c'est-à-dire break 2;) pour spécifier la quantité de niveaux de boucles imbriquées dont vous voulez sortir, mais C ++ ne le fait pas. Vous devrez le résoudre en utilisant un booléen que vous définissez sur false avant la boucle, défini sur true dans la boucle si vous voulez rompre, plus une pause conditionnelle après la boucle imbriquée, vérifiant si le booléen a été défini sur true et casse si oui.
Je sais que c'est un ancien poste. Mais je proposerais une réponse un peu logique et plus simple.
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;
}
}
}
j = conditionj
cela ne fonctionnera pas si vous avez un prédicat complexe à la place de j < conditionj
.
Brisez n'importe quel nombre de boucles par une seule bool
variable, voir ci-dessous:
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;
}
}
Dans ce code, nous avons break;
toutes les boucles.
Je ne sais pas si cela en vaut la peine, mais vous pouvez émuler les boucles nommées de Java avec quelques macros simples:
#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
Exemple d'utilisation:
#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);
}
}
}
Un autre exemple:
#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);
}
Vous pouvez utiliser 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
Si vous devez sortir de plusieurs boucles à la fois, c'est souvent une exception de toute façon.
Sortir d'une boucle for est un peu étrange pour moi, car la sémantique d'une boucle for indique généralement qu'elle s'exécutera un nombre spécifié de fois. Cependant, ce n'est pas mauvais dans tous les cas; si vous recherchez quelque chose dans une collection et que vous souhaitez vous casser après l'avoir trouvé, c'est utile. Il n'est cependant pas possible de sortir des boucles imbriquées en C ++; c'est dans d'autres langues grâce à l'utilisation d'une pause étiquetée. Vous pouvez utiliser une étiquette et un goto, mais cela pourrait vous donner des brûlures d'estomac la nuit ..? Cela semble être la meilleure option.