私はこのようなコードを書いています:
while(true) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
break; // **HERE, I want to break out of the loop itself**
}
}
それを行う直接的な方法はありますか?
フラグを使用して、スイッチの直後に条件付きブレークを配置することでループから抜けることができます。 C++にこのためのコンストラクトが既にあるかどうかを知りたいだけです。
次のコードは、言語や目的の機能に関係なく、不適切な形式と見なす必要があります。
_while( true ) {
}
_
while( true )
ループは、次の理由で不適切な形式です。
while(true)
を使用する場合、ループに実際に終了条件がない場合に、簡潔に通信する能力を失います。 (おそらく、これはすでに起こっているので、要点は議論の余地がある。)次のコードのほうが適切な形式です。
_while( isValidState() ) {
execute();
}
bool isValidState() {
return msg->state != DONE;
}
_
フラグなし。いいえgoto
。例外なし。簡単に変更できます。読みやすい。簡単に修正できます。さらに、コード:
2番目のポイントは重要です。コードがどのように機能するかを知らずに、誰かがメインループに他のスレッド(またはプロセス)にCPU時間を持たせるように頼んだ場合、2つの解決策が思い浮かびます:
一時停止を簡単に挿入します。
_while( isValidState() ) {
execute();
sleep();
}
_
実行のオーバーライド:
_void execute() {
super->execute();
sleep();
}
_
このコードは、switch
が埋め込まれたループよりも単純です(したがって、読みやすくなっています)。 isValidState
メソッドは、ループを継続するかどうかのみを決定する必要があります。メソッドの主力はexecute
メソッドに抽象化する必要があります。これにより、サブクラスがデフォルトの動作(埋め込みswitch
およびgoto
を使用する難しいタスク)をオーバーライドできます。
StackOverflowに投稿された次の回答(Pythonの質問)と対比):
_while True:
choice = raw_input('What do you want? ')
if choice == 'restart':
continue
else:
break
print 'Break!'
_
対:
_choice = 'restart';
while choice == 'restart':
choice = raw_input('What do you want? ')
print 'Break!'
_
ここで、_while True
_は、誤解を招くような過度に複雑なコードになります。
goto
を使用できます。
while ( ... ) {
switch( ... ) {
case ...:
goto exit_loop;
}
}
exit_loop: ;
別の解決策は、continue
と組み合わせてキーワードbreak
を使用することです。
for (;;) {
switch(msg->state) {
case MSGTYPE
// code
continue; // continue with loop
case DONE:
break;
}
break;
}
continue
ステートメントを使用して、ループを継続する各ケースラベルを終了し、break
ステートメントを使用して、ループを終了するケースラベルを終了します。
もちろん、このソリューションは、switchステートメントの後に実行する追加のコードがない場合にのみ機能します。
これを行うきちんとした方法は、これを関数に入れることです:
int yourfunc() {
while(true) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
return;
}
}
}
オプション(ただし、「悪い習慣」):既に示唆したように、gotoを使用するか、スイッチ内で例外をスローできます。
私の知る限り、C++には「ダブルブレーク」や同様の構造はありません。最も近いのはgoto
です。これは、その名前には意味がありませんが、言語には理由があるために存在します。慎重に慎重に使用する限り、実行可能なオプションです。
スイッチを次のような別の関数に入れることができます。
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())
;
Gotoが気に入らなくても、例外を使用してループを終了しないでください。次のサンプルは、それがどれほどいかを示しています。
_try {
while ( ... ) {
switch( ... ) {
case ...:
throw 777; // I'm afraid of goto
}
}
}
catch ( int )
{
}
_
this answerのようにgoto
を使用します。この場合、goto
は他のオプションよりもコードを明確にします。 this の質問が役立つことを願っています。
しかし、文字列while(true)
のため、goto
を使用することが唯一のオプションであると思います。ループのリファクタリングを検討する必要があります。私は次の解決策を想定しています:
_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 ...
}
_
この場合、ループから抜け出すためのC++コンストラクトはありません。
フラグを使用してループを中断するか、(必要に応じて)コードを関数に抽出してreturn
を使用します。
Gotoを使用することもできますが、ループを停止するフラグを設定することをお勧めします。次に、スイッチから抜け出します。
いいえ、キーワード "break"が既にswitchブロックを終了するために予約されているため、C++にはこのための構造がありません。または、終了フラグを指定したdo..while()で十分です。
do {
switch(option){
case 1: ..; break;
...
case n: .. ;break;
default: flag = false; break;
}
} while(flag);
Whileループの条件を修正するだけで、問題が解消されないのはなぜですか?
while(msg->state != DONE)
{
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
// We can't get here, but for completeness we list it.
break; // **HERE, I want to break out of the loop itself**
}
}
おもう;
while(msg->state != mExit)
{
switch(msg->state)
{
case MSGTYPE: // ...
break;
case DONE:
// ..
// ..
msg->state =mExit;
break;
}
}
if (msg->state ==mExit)
msg->state =DONE;
説明の深さを考えると、これがどれほど簡単か驚かされます...必要なものはすべてここにあります...
bool imLoopin = true;
while(imLoopin) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
imLoopin = false;
break;
}
}
笑!!本当に!必要なのはそれだけです! 1つの追加変数!
最も簡単な方法は、SWITCHを実行する前に単純なIFを配置し、そのIFがループを終了するための条件をテストすることです。
C++のbreak
キーワードは、最もネストされた囲み反復またはswitch
ステートメントのみを終了します。したがって、switch
ステートメント内でwhile (true)
ループから直接抜け出すことはできません。ただし、次のコードを使用することもできます。これは、このタイプの問題の優れたパターンだと思います。
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();
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**
}
}
同じ問題が発生し、フラグを使用して解決しました。
bool flag = false;
while(true) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
flag = true; // **HERE, I want to break out of the loop itself**
}
if(flag) break;
}