138

次のようなコードを書いています。

while(true) {
    switch(msg->state) {
    case MSGTYPE: // ... 
        break;
    // ... more stuff ...
    case DONE:
        break; // **HERE, I want to break out of the loop itself**
    }
}

それを行う直接的な方法はありますか?

フラグを使用して、スイッチの直後に条件付きブレークを配置することでループから抜け出すことができることを知っています。C++ にこのための構造が既にあるかどうかを知りたいだけです。

4

20 に答える 20

197

使用できますgoto

while ( ... ) {
   switch( ... ) {
     case ...:
         goto exit_loop;

   }
}
exit_loop: ;
于 2009-09-14T06:53:40.657 に答える
68

別の解決策は、キーワードcontinueを、と組み合わせて使用​​することbreakです。

for (;;) {
    switch(msg->state) {
    case MSGTYPE:
        // code
        continue; // continue with loop
    case DONE:
        break;
    }
    break;
}

ステートメントを使用してcontinue、ループを続行する各ケースラベルを終了し、breakステートメントを使用して、ループを終了する必要があるケースラベルを終了します。

もちろん、このソリューションは、switchステートメントの後に実行する追加のコードがない場合にのみ機能します。

于 2009-09-14T07:41:52.570 に答える
53

前提

次のコードは、言語や目的の機能に関係なく、不適切な形式と見なす必要があります。

while( true ) {
}

引数のサポート

while( true )ループは次の理由で貧弱な形式です。

  • whileループの暗黙のコントラクトを解除します。
    • whileループ宣言は、唯一の終了条件を明示的に示す必要があります。
  • 永久にループすることを意味します。
    • 終了句を理解するには、ループ内のコードを読み取る必要があります。
    • 永久に繰り返されるループは、ユーザーがプログラム内からプログラムを終了することを防ぎます。
  • 非効率的です。
    • 「true」のチェックを含む、複数のループ終了条件があります。
  • バグが発生しやすいです。
    • 反復ごとに常に実行されるコードをどこに配置するかを簡単に決定することはできません。
  • 不必要に複雑なコードにつながります。
  • 自動ソースコード分析。
    • バグの発見、プログラムの複雑さの分析、セキュリティチェック、またはコードを実行せずに他のソースコードの動作を自動的に導き出すために、初期の破壊条件を指定すると、アルゴリズムが有用な不変条件を決定できるため、自動ソースコード分析メトリックが向上します。
  • 無限ループ。
    • 誰もが常にwhile(true)無限ではないループを使用する場合、ループに終了条件が実際にない場合、簡潔に通信する機能が失われます。(おそらく、これはすでに起こっているので、要点は議論の余地があります。)

「GoTo」の代替

次のコードの方が適切です。

while( isValidState() ) {
  execute();
}

bool isValidState() {
  return msg->state != DONE;
}

利点

フラグなし。いいえgoto。例外なし。簡単に交換できます。読みやすい。簡単に修正できます。さらに、コード:

  1. ループ自体からループのワークロードの知識を分離します。
  2. コードを管理している人が機能を簡単に拡張できるようにします。
  3. 複数の終了条件を1か所に割り当てることができます。
  4. 終了句を実行するコードから分離します。
  5. 原子力発電所にとってより安全です。;-)

2番目のポイントは重要です。コードがどのように機能するかを知らなくても、誰かがメインループに他のスレッド(またはプロセス)にCPU時間を持たせるように依頼された場合、2つの解決策が思い浮かびます。

オプション1

一時停止をすぐに挿入します。

while( isValidState() ) {
  execute();
  sleep();
}

オプション#2

オーバーライド実行:

void execute() {
  super->execute();
  sleep();
}

このコードは、が埋め込まれたループよりも単純です(したがって読みやすくなります)switchisValidStateメソッドは、ループを続行するかどうかのみを決定する必要があります。メソッドの主力はメソッドに抽象化する必要があります。これにより、サブクラスがデフォルトの動作(埋め込みとexecuteを使用する難しいタスク)をオーバーライドできるようになります。switchgoto

Pythonの例

StackOverflowに投稿された次の回答(Pythonの質問に対する)を比較してください:

  1. 永遠にループします。
  2. ユーザーに選択内容を入力してもらいます。
  3. ユーザーの入力が「restart」の場合は、ループを永久に継続します。
  4. それ以外の場合は、ループを永久に停止します。
  5. 終わり。
コード
while True: 
    choice = raw_input('What do you want? ')

    if choice == 'restart':
        continue
    else:
        break

print 'Break!' 

対:

  1. ユーザーの選択を初期化します。
  2. ユーザーの選択が「restart」という単語である間にループします。
  3. ユーザーに選択内容を入力してもらいます。
  4. 終わり。
コード
choice = 'restart';

while choice == 'restart': 
    choice = raw_input('What do you want? ')

print 'Break!'

ここではwhile True、誤解を招き、過度に複雑なコードになります。

于 2009-09-14T07:14:53.463 に答える
24

これを行うためのきちんとした方法は、これを関数に入れることです:

int yourfunc() {

    while(true) {

        switch(msg->state) {
        case MSGTYPE: // ... 
            break;
        // ... more stuff ...
        case DONE:
            return; 
        }

    }
}

オプションで(しかし「悪い習慣」):すでに示唆されているように、gotoを使用するか、スイッチ内で例外をスローできます。

于 2009-09-14T06:56:47.500 に答える
15

私の知る限り、C++には「ダブルブレーク」または同様の構造はありません。最も近いのはgoto- で、その名前には悪い意味合いがありますが、理由があって言語に存在します - 慎重に控えめに使用されている限り、実行可能なオプションです。

于 2009-09-14T06:54:38.767 に答える
9

次のような別の機能にスイッチを配置できます。

bool myswitchfunction()
{
    switch(msg->state) {
    case MSGTYPE: // ... 
        break;
    // ... more stuff ...
    case DONE:
        return false; // **HERE, I want to break out of the loop itself**
    }
    return true;
}

while(myswitchfunction())
    ;
于 2009-09-14T07:35:58.340 に答える
7

gotoが気に入らない場合でも、例外を使用してループを終了しないでください。次のサンプルは、それがどれほど醜いかを示しています。

try {
  while ( ... ) {
    switch( ... ) {
      case ...:
        throw 777; // I'm afraid of goto
     }
  }
}
catch ( int )
{
}

私はこの答えgotoのように使用します。この場合、他のオプションよりもコードが明確になります。この質問がお役に立てば幸いです。goto

gotoしかし、文字列があるため、ここでは使用することが唯一のオプションだと思いますwhile(true)。ループのリファクタリングを検討する必要があります。私は次の解決策を想定しています:

bool end_loop = false;
while ( !end_loop ) {
    switch( msg->state ) {
    case MSGTYPE: // ... 
        break;
    // ... more stuff ...
    case DONE:
        end_loop = true; break;
    }
}

または次のようにさえ:

while ( msg->state != DONE ) {
    switch( msg->state ) {
    case MSGTYPE: // ... 
        break;
    // ... more stuff ...
}
于 2009-09-14T07:15:38.560 に答える
5

この場合、ループを抜け出すための C++ 構造はありません。

フラグを使用してループを中断するか、(適切な場合) コードを関数に抽出して使用しますreturn

于 2009-09-14T06:59:56.430 に答える
4

いいえ、キーワード「break」が switch ブロックを終了するためにすでに予約されていることを考えると、C++ にはこのための構造がありません。または、終了フラグを指定した do..while() で十分です。

do { 
    switch(option){
        case 1: ..; break;
        ...
        case n: .. ;break;
        default: flag = false; break;
    }
} while(flag);
于 2017-04-07T06:37:33.463 に答える
2

goto を使用することもできますが、ループを停止するフラグを設定することをお勧めします。次に、スイッチから抜け出します。

于 2009-09-14T06:54:37.457 に答える
1

おもう;

while(msg->state != mExit) 
{
    switch(msg->state) 
    {
      case MSGTYPE: // ...
         break;
      case DONE:
      //  .. 
      //  ..
      msg->state =mExit;
      break;
    }
}
if (msg->state ==mExit)
     msg->state =DONE;
于 2014-01-07T08:52:30.537 に答える
1

説明の深さを考えると、これがどれほど単純であるかに驚かされます...必要なものはすべてここにあります...

bool imLoopin = true;

while(imLoopin) {

    switch(msg->state) {

        case MSGTYPE: // ... 
            break;

        // ... more stuff ...

        case DONE:
            imLoopin = false;
            break;

    }

}

笑!!本当!それだけです!追加の変数が 1 つ!

于 2011-05-04T07:57:39.783 に答える
0

C++のbreakキーワードは、最もネストされた囲み反復またはswitchステートメントのみを終了します。したがって、ステートメントwhile (true)内でループから直接抜け出すことはできません。switchただし、次のコードを使用できます。これは、このタイプの問題の優れたパターンだと思います。

for (; msg->state != DONE; msg = next_message()) {
    switch (msg->state) {
    case MSGTYPE:
        //...
        break;

    //...
    }
}

msg->state等しいときに何かを行う必要がある場合(クリーンアップ ルーチンの実行など)、そのコードをループDONEの直後に配置します。forつまり、現在持っている場合:

while (true) {
    switch (msg->state) {
    case MSGTYPE:
        //... 
        break;

    //...

    case DONE:
        do_cleanup();
        break;
    }

    if (msg->state == DONE)
        break;

    msg = next_message();
}

次に、代わりに使用します。

for (; msg->state != DONE; msg = next_message()) {
    switch (msg->state) {
    case MSGTYPE:
        //...
        break;

    //...
    }
}

assert(msg->state == DONE);
do_cleanup();
于 2011-01-04T15:32:19.813 に答える
0
while(MyCondition) {
switch(msg->state) {
case MSGTYPE: // ... 
    break;
// ... more stuff ...
case DONE:
   MyCondition=false; // just add this code and you will be out of loop.
    break; // **HERE, you want to break out of the loop itself**
}
}
于 2011-06-22T07:44:28.270 に答える
0

それを行う最も簡単な方法は、 SWITCH を実行する前に単純な IF を配置することです。その IF は、ループを終了するための条件をテストします。

于 2009-11-12T09:06:38.790 に答える
-2

C++ の構文をよく覚えていれば、breakfor のようにステートメントにラベルを追加できますgoto。したがって、あなたが望むものは簡単に書かれます:

while(true) {
    switch(msg->state) {
    case MSGTYPE: // ...
        break;
    // ... more stuff ...
    case DONE:
        break outofloop; // **HERE, I want to break out of the loop itself**
    }
}

outofloop:
// rest of your code here
于 2009-09-14T17:13:56.573 に答える
-3
  while(true)
  {
    switch(x)
    {
     case 1:
     {
      break;
     }
    break;
   case 2:
    //some code here
   break;
  default:
  //some code here
  }
}
于 2012-01-30T17:45:04.103 に答える