134

ループ内でbreakステートメントを使用するのは悪い習慣ですか?for

たとえば、配列内の値を検索しています。for ループ内で比較し、値が見つかったときに for ループbreak;を終了します。

これは悪い習慣ですか?変数を定義しvFound、値が見つかったらそれを true に設定vFoundし、forステートメント条件をチェックインするという代替手段が使用されているのを見てきました。しかし、この目的のためだけに新しい変数を作成する必要がありますか?

通常の C または C++ for ループのコンテキストで質問しています。

PS: MISRA コーディング ガイドラインでは、break を使用しないようにアドバイスしています。

4

19 に答える 19

146

いいえ、休憩は正しい解決策です。

ブール変数を追加すると、コードが読みにくくなり、エラーの潜在的な原因が追加されます。

于 2010-10-13T10:27:30.303 に答える
133

ここにはたくさんの答えがありますが、私はこれがまだ言及されているのを見ていません:

整然とした、読みやすいループを作成すると、forループの使用breakまたはforループでの「危険」のほとんどが無効になります。continueループの本体が複数の画面長にまたがり、ネストされたサブブロックが複数ある場合は、そうです。中断後に一部のコードが実行されないことを簡単に忘れることができます。ただし、ループが短くて要点がある場合は、breakステートメントの目的を明確にする必要があります。

ループが大きくなりすぎている場合は、代わりにループ内で1つ以上の名前の付いた関数呼び出しを使用してください。そうしないようにする唯一の本当の理由は、ボトルネックを処理するためです。

于 2010-10-13T17:16:54.437 に答える
54

「break」ステートメントを含むあらゆる種類の専門的なコードを見つけることができます。必要なときにいつでもこれを使用することは完全に理にかなっています。あなたの場合、このオプションは、ループから抜け出すためだけに別の変数を作成するよりも優れています。

于 2010-10-13T10:40:21.130 に答える
51

breakループと同様に使用してもcontinueまったく問題forありません。

コードを簡素化し、可読性を向上させます。

于 2010-10-13T10:18:06.647 に答える
24

悪い習慣とはかけ離れて、Python (および他の言語?) はforループ構造を拡張したため、その一部はループが実行されない場合にのみ実行されます。 break

for n in range(5):
    for m in range(3):
        if m >= n:
            print('stop!')
            break
        print(m, end=' ')
    else:
        print('finished.')

出力:

stop!
0 stop!
0 1 stop!
0 1 2 finished.
0 1 2 finished.

ない同等のコードbreakと便利なコードelse

for n in range(5):
    aborted = False
    for m in range(3):
        if not aborted:
            if m >= n:
                print('stop!')
                aborted = True
            else:            
                print(m, end=' ')
    if not aborted:
        print('finished.')
于 2010-10-13T13:54:02.843 に答える
17

一般的なルール: ルールに従うために、ルールを破るよりも厄介で読みにくいことを行う必要がある場合は、ルールを破ります。

何かを見つけるまでループする場合、抜けたときに見つかったものと見つからなかったものを区別するという問題に遭遇します。あれは:

for (int x=0;x<fooCount;++x)
{
  Foo foo=getFooSomehow(x);
  if (foo.bar==42)
    break;
}
// So when we get here, did we find one, or did we fall out the bottom?

フラグを設定するか、「見つかった」値を null に初期化できます。しかし

そのため、一般的に、検索を関数にプッシュすることを好みます。

Foo findFoo(int wantBar)
{
  for (int x=0;x<fooCount;++x)
  {
    Foo foo=getFooSomehow(x);
    if (foo.bar==wantBar)
      return foo;
  }
  // Not found
  return null;
}

これは、コードを整理するのにも役立ちます。本線では「find」が一文になり、条件が複雑な場合は一度しか書かない。

于 2010-10-13T14:33:00.440 に答える
15

break ステートメントを使用しても本質的に問題はありませんが、ネストされたループは混乱を招く可能性があります。読みやすさを向上させるために、多くの言語 (少なくとも Java はサポートしています) は、読みやすさを大幅に向上させるラベルの分割をサポートしています。

int[] iArray = new int[]{0,1,2,3,4,5,6,7,8,9};
int[] jArray = new int[]{0,1,2,3,4,5,6,7,8,9};

// label for i loop
iLoop: for (int i = 0; i < iArray.length; i++) {

    // label for j loop
    jLoop: for (int j = 0; j < jArray.length; j++) {

        if(iArray[i] < jArray[j]){
            // break i and j loops
            break iLoop;
        } else if (iArray[i] > jArray[j]){  
            // breaks only j loop
            break jLoop;
        } else {
            // unclear which loop is ending
            // (breaks only the j loop)
            break;
        }
    }
}

break (および return) ステートメントは循環的な複雑さを増すことが多く、コードがすべてのケースで正しいことを行っていることを証明するのが難しくなります。

特定のアイテムのシーケンスを反復処理する際にブレークを使用することを検討している場合は、データを保持するために使用されるデータ構造を再検討することをお勧めします。Set や Map などを使用すると、より良い結果が得られる場合があります。

于 2010-10-13T16:24:35.660 に答える
14

breakは、使用するのに完全に受け入れられるステートメントです(つまり、 continue、btw)。それはすべてコードの可読性に関するものです-過度に複雑なループなどがない限り、それは問題ありません。

彼らが後藤と同じリーグだったわけではありません。:)

于 2010-10-13T11:09:34.103 に答える
13

言語によって異なります。ここでブール変数を確認できる可能性がありますが:

for (int i = 0; i < 100 && stayInLoop; i++) { ... }

配列を繰り返し処理するときはできません。

for element in bigList: ...

とにかく、break両方のコードをより読みやすくします。

于 2010-10-13T10:21:18.927 に答える
8

の使用を推奨する他の人に同意しbreakます。明らかな必然的な質問は、なぜ誰かが他の方法を推奨するのでしょうか? ええと... break を使用すると、ブロック内の残りのコードと残りの反復がスキップされます。これにより、次のようなバグが発生することがあります。

  • forブロックの上部で取得されたリソースは、下部で解放される可能性があります (これはループ内のブロックにも当てはまります) break。 C++ では、"RAII" を使用して、信頼性の高い例外セーフな方法でこれを処理します。基本的に、スコープがどのように終了しても、オブジェクト デストラクタは確実にリソースを解放します)。

  • for他の非局所化された終了条件があることに気付かずに、誰かがステートメントの条件テストを変更する可能性があります

  • ndim's answer は、比較的一貫したループ実行時間を維持するために s を避ける人がいるかもしれないことを観察していますが、それが保持されないブール早期終了制御変数の使用とbreak比較していましたbreak

時々、そのようなバグを観察する人々は、この「ブレークなし」ルールによってそれらを防止/軽減できることに気づきます...実際、「構造化プログラミング」と呼ばれる「より安全な」プログラミングのための関連する戦略全体があり、各関数が持つはずです単一の入口と出口点も (つまり、goto なし、アーリー リターンなし)。いくつかのバグを排除するかもしれませんが、間違いなく他のバグを導入します. なぜ彼らはそれをするのですか?

  • 特定のスタイルのプログラミング/コードを奨励する開発フレームワークがあり、これがその限られたフレームワークで純利益を生み出すという統計的証拠がある、または
  • そのようなフレームワーク内でのプログラミング ガイドラインまたは経験の影響を受けている、または
  • 彼らはただの独裁的な馬鹿です、または
  • 上記のいずれか + 歴史的な慣性 (正当化が最新の C++ よりも C に適用されるという点で関連)。
于 2010-10-13T11:57:27.650 に答える
6

あなたの例では、 forループの反復回数がわかりません。代わりにwhileループを使用しないのはなぜですか。最初は反復回数を不確定にすることができます。

したがって、ループはwhileループとしてより適切に記述できるため、通常はbreak ステートメントを使用する必要はありません。

于 2010-10-13T10:21:44.090 に答える
5

使用するのは完全に有効ですbreak-他の人が指摘しているように、goto.

vFound値が配列で見つかったかどうかをループの外側で確認する場合は、変数を使用することをお勧めします。また、保守性の観点からも、終了基準を示す共通のフラグがあると便利な場合があります。

于 2010-10-13T12:53:13.820 に答える
5

現在取り組んでいるコードベース (40,000 行の JavaScript) を分析しました。

それらのうち、 22のbreakステートメントしか見つかりませんでした:

  • 19 個がswitchステートメント内で使用されました (合計で 3 つの switch ステートメントしかありません!)。
  • 2 はforループ内で使用されました。このコードは、別の関数にリファクタリングされ、returnステートメントに置き換えられるとすぐに分類されました。
  • 最後のbreak内部whileループについては...git blame誰がこのがらくたを書いたかを確認するために走りました!

したがって、私の統計によると、が 以外で使用されている場合、それはコードの匂いです。breakswitch

発言も検索しましたcontinue。何も見つかりませんでした。

于 2010-10-13T17:21:24.677 に答える
4

エンベデッドワールドには、次の構造を使用するコードがたくさんあります。

    while(1)
    { 
         if (RCIF)
           gx();
         if (command_received == command_we_are_waiting_on)
           break;
         else if ((num_attempts > MAX_ATTEMPTS) || (TickGet() - BaseTick > MAX_TIMEOUT))
           return ERROR;
         num_attempts++;
    }
    if (call_some_bool_returning_function())
      return TRUE;
    else
      return FALSE;

これは非常に一般的な例であり、カーテンの後ろで多くのことが起こっており、特に割り込みが発生しています。これを定型コードとして使用しないでください。例を説明しようとしているだけです。

私の個人的な意見では、この方法でループを作成することは、ループに無期限に留まらないように適切な注意を払う限り、何も問題はありません。

于 2010-10-13T14:11:23.853 に答える
4

その時点で STOP 処理を完了したい場合、それが悪い習慣になる理由はわかりません。

于 2010-10-13T16:21:35.890 に答える
3

ユースケースによって異なります。for ループの実行時間を一定にする必要があるアプリケーションがあります (たとえば、いくつかのタイミング制約を満たすため、またはタイミング ベースの攻撃からデータ内部を隠すため)。

forそのような場合、フラグを設定し、すべてのループ反復が実際に実行された後にのみフラグ値をチェックすることも理にかなっています。もちろん、すべての for ループの反復でコードを実行する必要がありますが、それでもほぼ同じ時間がかかります。

実行時間を気にしない場合... と を使用break;continue;て、コードを読みやすくします。

于 2010-10-13T11:02:17.367 に答える
2

私の会社のCdevで使用されているMISRA98ルールでは、breakステートメントは使用されません...

編集:MISRA'04ではブレークが許可されています

于 2010-10-13T11:05:27.443 に答える
0

もちろん、break;for ループまたは foreach ループを停止するソリューションです。foreach および for ループの php で使用したところ、動作することがわかりました。

于 2010-10-13T11:01:05.573 に答える
0

forループの一番上にチェックを入れるのは理にかなっていると思います

for(int i = 0; i < myCollection.Length && myCollection[i].SomeValue != "Break Condition"; i++)
{
//loop body
}

または、最初に行を処理する必要がある場合

for(int i = 0; i < myCollection.Length && (i == 0 ? true : myCollection[i-1].SomeValue != "Break Condition"); i++)
{
//loop body
}

このようにして、途切れることなく特異な身体機能を持つことができます。

for(int i = 0; i < myCollection.Length && (i == 0 ? true : myCollection[i-1].SomeValue != "Break Condition"); i++)
{
    PerformLogic(myCollection[i]);
}

Break を独自の関数に移動するように変更することもできます。

for(int i = 0; ShouldContinueLooping(i, myCollection); i++)
{
    PerformLogic(myCollection[i]);
}
于 2010-10-13T16:22:13.653 に答える