368

関数を使用して、breakいくつかのネストされたforループを終了することは可能ですか?

もしそうなら、あなたはこれをどのようにやっていきますか?break出口のループ数を制御することもできますか?

4

20 に答える 20

307

いいえ、で台無しにしないでくださいbreak。これは、を使用するための最後の拠点ですgoto

于 2009-08-10T23:24:17.920 に答える
281

AFAIK、C ​​++は、Javaや他の言語がサポートしているように、名前付けループをサポートしていません。gotoを使用するか、使用するフラグ値を作成できます。各ループの最後に、フラグ値を確認します。trueに設定されている場合は、その反復から抜け出すことができます。

于 2009-08-10T23:20:14.900 に答える
113

ラムダを使用して明示的な回答を追加するだけです。

  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のみですが、非常に便利だと思います。

于 2015-10-16T15:56:07.163 に答える
61

ネストされたループから抜け出すための別のアプローチは、両方のループを別の関数に分解し、return終了するときにその関数から分解することです。

もちろん、これはreturn、関数の最後以外の場所から明示的に行うべきかどうかという別の議論を引き起こします。

于 2009-08-10T23:39:30.400 に答える
37

breakは、それを含む最も内側のループのみを終了します。

gotoを使用して、任意の数のループから抜け出すことができます。

もちろん、 gotoはしばしば有害と見なされます。

ブレーク機能を使用するのは適切ですか[...]?

breakとgotoを使用すると、プログラムの正しさを推論するのが難しくなる可能性があります。これに関する議論については、ここを参照してください: ダイクストラは正気ではありませんでした。

于 2009-08-10T23:20:22.403 に答える
30

これはどう?

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;
            }
        }
    }
}
于 2012-03-30T15:37:24.257 に答える
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;
        }
    }

}
于 2011-11-03T08:27:56.623 に答える
22

gotoネストされたループから抜け出すためにとラベルを使用するコード例:

for (;;)
  for (;;)
    goto theEnd;
theEnd:
于 2015-03-10T23:11:08.913 に答える
12

いくつかのネストされたループから抜け出すための1つの優れた方法は、コードを関数にリファクタリングすることです。

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;
            }
        }
    }
}
于 2013-06-12T04:00:44.830 に答える
7

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
于 2016-09-27T14:57:46.120 に答える
6

私はこれが古いスレッドであることを知っていますが、これは本当に言う必要があり、他にそれを言う場所がないと感じています。ここにいる全員は、gotoを使用してください。使っただけです。

ほとんどすべてのように、gotoは100%「悪い」または「良い」ではありません。少なくとも2つの用途があります。gotoを使用し、他の用途には使用しない場合は、100%大丈夫であるだけでなく、プログラムはそれがない場合よりもさらに読みやすくなります。 、それはあなたの意図をはるかに明確にするので(それを回避する方法はありますが、私はそれらのすべてがはるかに不格好であることがわかりました):

  1. ネストされたループから抜け出し、
  2. エラー処理(つまり、関数の最後でクリーンアップルーチンにジャンプして、失敗コードを返し、メモリの割り当てを解除します)。

「まあまあ」のようなルールを独断的に受け入れるのではなく、その感情が主張されている理由を理解し、感情の文字ではなく「理由」に従ってください。これを知らないと、私も多くの問題を抱えました。独断的に物事を「悪」と呼ぶことは、物事自体よりも有害である可能性があります。最悪の場合、あなたはただ悪いコードを手に入れます-そしてあなたはあなたが用心深いと聞いている限りあなたがそれを正しく使用していなかったことを知っています、しかしあなたが独断を満足させようとして自分自身を苦しめているなら、それはもっと悪いと思います。

「 goto」が「evil」と呼ばれるのは、通常のif、fors、whileの代わりに「goto」を使用してはならないためです。そして、なぜそれ?試してみて、通常の制御ロジックステートメントの代わりに「goto」を常に使用してみてください。次に、制御ロジックを使用して同じコードをもう一度記述してみてください。どちらが見栄えがよく、どちらが混乱しているのかを教えてください。 。どうぞ。(ボーナス:gotoのみのコードに今すぐ新しい機能を追加してみてください。)それが「悪」であり、「悪」の周りに適切なスコープ資格がある理由です。breakCの" "コマンドの欠点を短絡するためにそれを使用することはありませんgotoが何を達成することになっているのかをコードから明確にする限り、問題のある使用法(たとえば、「nestedBreak」などのラベルを使用する)。ネストされたループから抜け出すのは非常に自然です。

(または、より簡単に言うと、gotoを使用してループから抜け出します。これはさらに望ましいと思います。gotoを使用してループを作成しないでください。これは「悪」です。)

そして、あなたが独断的であるかどうかをどうやって知るのですか?「xyzisevil」ルールに従うと、コードを回避しようとしているためにコードが理解しにくくなる場合(各ループに条件文を追加したり、フラグ変数を追加したり、その他のトリックを追加したりするなど)。 、それならあなたは独断的である可能性が非常に高いです。

優れたコーディング習慣以上に、優れた思考習慣を学ぶことに代わるものはありません。前者は後者の前にあり、前者が採用されると後者が続くことがよくあります。しかし、問題は、私があまりにも頻繁に見つけることであり、後者は十分に説明されていません。何を考えるべきか、何を考えるべきかそしてその理由を言わずに、単に「これは悪い」と「これはもっと考える必要がある」と言う人が多すぎます。そして、それは大きな恥です。

(FWIW、C ++では、ネストされたループから抜け出す必要はありますが、エラーコードは必要ありません。その場合、エラーコードを処理するために常に例外を使用し、頻繁に発生しない限り、エラーコードを返さないでください。例外のスローとキャッチは、パフォーマンスの問題を引き起こします。たとえば、需要の高いサーバーコードのタイトなループでは、おそらく[「例外」は「めったに使用されない」と言う人もいるかもしれませんが、それは考え抜かれた独断主義の別の部分です。いいえ、少なくともそのドグマを打ち負かした後の私の経験では、それらは物事をはるかに明確にします-制御フローとして使用するなど、エラー処理以外のことをするためにそれらを悪用しないでください。事実上「goto」と同じです。それらをすべて、エラー処理のためだけに使用します。それが彼らの目的です。]。)

于 2020-07-24T00:49:52.943 に答える
3

ステートメントは、それが現れるbreak最も近い囲み、、、またはステートメントの実行をdo終了します。制御は、終了したステートメントに続くステートメントに渡されます。forswitchwhile

msdnから。

于 2009-08-10T23:19:21.673 に答える
3

goto私はこの状況でaが有効だと思います:

break/をシミュレートするには、次のcontinueようにします。

壊す

for ( ;  ;  ) {
    for ( ;  ;  ) {
        /*Code here*/
        if (condition) {
            goto theEnd;
        }
    }
}
theEnd:

継続する

for ( ;  ; ) {
    for ( ;  ;  ) {
        /*Code here*/
        if (condition) {
            i++;
            goto multiCont;
        }
    }
    multiCont:
}
于 2015-11-27T09:58:51.280 に答える
3

それが価値があるかどうかはわかりませんが、いくつかの単純なマクロを使用して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);
}
于 2020-04-26T22:30:21.897 に答える
1

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;、すべてのループがあります。

于 2019-07-17T11:46:12.010 に答える
0

PHPなどの他の言語は、ブレーク(つまり、ブレーク2;)のパラメーターを受け入れて、ブレークアウトするネストされたループレベルの量を指定しますが、C++は受け入れません。ループの前にfalseに設定したブール値を使用して解決する必要があります。ブレークする場合はループ内でtrueに設定し、ネストされたループの後に条件付きのブレークを設定して、ブール値がtrueに設定されているかどうかを確認します。はいの場合は中断します。

于 2009-08-10T23:23:07.937 に答える
0

私はこれが古い投稿であることを知っています。しかし、私は少し論理的で単純な答えを提案します。

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;
            }
        }
    }
于 2016-05-30T07:57:26.307 に答える
-1
  while (i<n) {
    bool shouldBreakOuter = false;
    for (int j=i + 1; j<n; ++j) {
      if (someCondition) {
          shouldBreakOuter = true;
      }
    }

    if (shouldBreakOuter == true)
      break;

  }
于 2017-10-21T15:37:10.083 に答える
-2

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

一度に複数のループから抜け出す必要がある場合、それはとにかく例外であることがよくあります。

于 2013-04-02T14:49:33.660 に答える
-5

forループのセマンティクスは通常、指定された回数実行されることを示しているため、forループから抜け出すのは少し奇妙です。ただし、すべての場合に悪いわけではありません。コレクション内の何かを検索していて、それを見つけた後で中断したい場合は、それが便利です。ただし、ネストされたループから抜け出すことは、C++では不可能です。ラベル付きの区切りを使用することにより、他の言語で使用されます。ラベルと後藤を使うこともできますが、夜は胸焼けをするかもしれません。しかし、最良の選択肢のようです。

于 2009-08-10T23:20:01.657 に答える