終了条件に達した場合、C ++でfor before時間を終了することは可能ですか?
-
03-07-2019 - |
質問
C ++でforループを終了できるかどうかを知りたいのですが、終了条件(正しい到達回数の反復とは異なる)が検証されます。例えば:
for (int i = 0; i < maxi; ++i)
for (int j = 0; j < maxj; ++j)
// But if i == 4 < maxi AND j == 3 < maxj,
// then jump out of the two nested loops.
これは次のLABELまたは最後のLABEL呼び出しとラベル付きブロックでPerlで可能であることを知っていますが、C ++でそれを行うことは可能ですか、それともwhileループを使用する必要がありますか?
ありがとう。
解決
return
キーワードを使用できます。ネストされたループをサブルーチンに移動し、サブルーチンを呼び出してネストされたループを実行し、サブルーチンから「戻る」ことでループを終了します。
他のヒント
<!> quot;にもかかわらず、goto
は有害と考えられます<!> quot;引数、これは<=>に最適な場所のようです。それは基本的にあなたがPerlでやっていることです。真剣に...代替案を検討してください:
追加の状態変数
for (int i=0; i<maxi; ++i) {
bool leaveLoop = false;
for (int j=0; j<maxj; ++j) {
if (i == 4 && j == 3) {
leaveLoop = true;
break; // leave the inner loop
}
}
if (leaveLoop) {
break; // leave the outside loop
}
}
例外のままにする
try {
for (int i=0; i<maxi; ++i) {
for (int j=0; j<maxj; ++j) {
if (i == 4 && j == 3) {
throw leave_loop();
}
}
}
} catch (leave_loop const&) {
}
複雑なロジック
int j = 0;
for (int i=0; i<maxi && !(i==4 && j==3); ++i) {
for (j=0; j<maxj && !(i==4 && j==3); ++j) {
// inner loop
}
}
<=>
for (int i=0; i<maxi; ++i) {
for (int j=0; j<maxj; ++j) {
if (i==4 && j==3) {
goto leave_loop;
}
}
}
leave_loop:
最後の1つはそれほど明確ではありませんか?そうだとは思わない。もう壊れやすいですか?私見、他のものは<=>バージョンと比較して非常にエラーが発生しやすく、脆弱です。ここの石鹸箱の上に立ってすみませんが、これはしばらく私を悩ませたものです;)
認識しなければならない唯一のことは、<=>と例外が非常に似ていることです。どちらも、リソースを漏らす可能性を開き、そうでない場合は慎重に扱います。
これをできる限り強調して(ただし丁寧に;-)言わせてください。
続行するかどうかを決定するテスト式は、ループの目的に関連するものであれば何でもかまいません。更新式は<!> quot;カウンタに追加する必要はありません<!> quot;。
for (int i = 0, j = 0; i < maxi && j < maxj && i != 4 && j != 3;) {
if (j < maxj) {
++j;
} else {
j = 0;
++i;
}
}
書き換えの1つの(かなり任意の)方法になります。
ポイントは、何らかの条件を確立することがインターレーションのポイントである場合、通常、継続/終了条件をより明示的に示す方法でループ(for
またはwhile
のいずれかを使用して)を書くことができることです
(実際に何が起こっているかの説明を投稿できる場合、上記のようにarbitrary意的ではない何かを書く可能性があります。)
1つのブレーク命令で 2つのループからジャンプすることはできませんが、gotoを使用して内側のループからすぐ外側にジャンプできます。
gotoがローカライズされていて、そうでない場合よりロジックが少ないことを意味する場合、完全に受け入れ可能なコードであると思います。追加のフラグ変数を使用するか、外側のループで比較できるように反復子変数を内側のループから引き上げると、コードの理解が容易になりません。
上記のすべての提案から、例外は通常の制御フローではなく例外的な状況のために予約する必要があるため、try / catchメカニズムの使用を避けます。
2番目の条件を適切に作成できれば、2つのブレークを使用しても問題ありません。この目的でブール値を使用することも適切であり、各forループの条件に配線することもできます。例:
bool exit_loops = false;
for (int a = 0; a < A && !exit_loops; ++a)
{
for (int b = 0; b < B && !exit_loops; ++b)
{
if (some_condition) exit_loops = true;
}
}
3つ以上のループを使用している場合、関数でループをラップし、関数を終了するためにreturnを使用する方が適切な場合があります(すべてのループも)。その後、ループの1つを除くすべてを削除できるようにコードをリファクタリングできます。これは、内部ループコードを実行する関数を呼び出すことなどによって行われます。
最後にこの状況でgotoを使用することを恐れないでください。通常、gotoは構造化されていない悪いプログラミングですが、場合によっては(このように)非常に便利です。
bool done = false;
for (int i = 0; i < maxi && !done; ++i)
for (int j = 0; j < maxj && !done; ++j)
if (i == 4 && i < maxi && j == 3 && j < maxj )
done = true;
else {
}
または、そのまま移動できます。かどうか:-)
C / C ++ではこのように飛び出すことはできません:
for (...)
{
for (...)
{
// from here...
}
}
// ...to here
gotoを使用しない。次のような構造が必要です:
for (...)
{
bool
exit = false;
for (...)
{
if (do_exit)
{
exit = true; // or set outer loop counter to end value
break;
}
}
if (exit)
{
break;
}
}
代わりに、throwとcatchを使用します-ただし、throwはフロー制御ではなく例外に実際に使用する必要があるので、それは素晴らしいことではありません。
きれいな方法は、内側のループを関数にすることです:
bool F ()
{
if inner loop terminates, return false else return true
}
void G ()
{
for (...)
{
if (!F ())
{
break;
}
}
}
for (int i = 0; i < maxi; ++i)
{
int j = 0;
for (j = 0; j < maxj; ++j)
{
if (i == 4 && j == 3) // i < maxi and j < maxj otherwise we would not be here
break; // exit inner loop
}
if (i == 4 && j == 3) // i < maxi and j < maxj otherwise we would not be here
break; // exit outer loop
}
gotoステートメントを使用できます、しかしそれは一般的に悪い習慣と考えられています。
他のオプションは、このようなことをすることです
int i;
int j = 0;
for (i = 0; i < maxi && !(i==4 && j==3); ++i)
for (j = 0; j < maxj && !(i==4 && j==3); ++j)
コードを読むことは、探偵の本を読むようなものであってはなりません(常に把握する必要があります)...
例:
Java:
iterate_rows:
for (int i = 0; i < maxi; ++i)
{
for (int j = 0; j < maxj; ++j)
{
if (i == 4 < maxi && j == 3 < maxj)
break iterate_rows;
else
continue iterate_rows;
}
}
iterate_rowsが破損することを理解する必要はありません。ただ読んでください。
C ++:
//iterate_rows:
for (int i = 0; i < maxi; ++i)
{
for (int j = 0; j < maxj; ++j)
{
if (i == 4 < maxi && j == 3 < maxj)
goto break_iterate_rows;
else
goto continue_iterate_rows;
}
continue_iterate_rows:;
}
break_iterate_rows:;
goto break_iterate_rows は、 break iterate_rows
の表示バージョンです。gotoとラベルの使用をこの種のコードのみに限定する場合、意図を理解することはできません。この種のコードでgotoとラベルの使用を制限すると、コードを分析したり理解したりするのではなく、コードを読むだけになります。邪悪なプログラマーであると非難されることはありません。
そして、この種のコードでgotoを本当に制限する場合、それらのくそったれがコードで何をするのかを理解する必要がないという習慣を身に付けることができます。追加の利点は、ブール値を導入して追跡する必要がないことです(これにより、コードの検出につながり、少し読みにくくなり、gotoを回避するという本来の目的に反します)
P.S。
これらのラベルをコメント(ループの前)とペアリングします。gotoステートメントを使用してこれらの行を読み終えるまでに、それらのgotoの意図はすでにわかっています
いくつかの提案があります:
-
throw .... <!> quot; try {} <!> quot;内に2つのループを配置します。そして<!> quot; catch <!> quot; <!> quot; throw <!> quot;条件について。
-
2つのループをメソッドに入れて、条件に戻ります。
-
後藤は、人々がそれを使用することで悪ではありません。...<!> quot; goto <!> quot;を使用できます。特にエラーを処理する場合、最も明確なコードになる可能性があります。私は20年間で使用していません。
トニー
私は常にgoto
ステートメントから離れようとしました(何らかの理由で学校と私の仕事で常に見下されていました)。 Daeminが提案したようなものを使用します。
次のような行に沿ってラベルを使用できます。
Outer:
for(...)
{
Inner:
for(...)
{
if(condition)
{
goto End;
}
}
}
End:
Javaでは、ラベルを渡して中断することができますか?
編集-gotoをOuterではなくEndに変更しましたが、ネガティブな担当者が正当化されるとは思いません。この回答は、最も簡単な方法を提供します。
for
構造を完全に再検討するもう1つの理由は、そのスコープが、ループの終了後に制御変数へのアクセスを妨げるためです。ループ内で変更されている変数の値は、さまざまな理由(検索の成功と失敗を区別するなど)に役立つ場合があります。以下に、a
という名前の正方配列でtarget
値を検索する小さな例を示します(SIZE
がゼロ以外の場合は、検索は不要です!):
int i = 0;
int j = 0;
while (i < SIZE && a[i][j] != target) { // still in array but not at target
if (SIZE <= ++j) { // fallen off the end of a row
j = 0;
++i;
}
}
後続のコードでは、i < SIZE
を使用して、目的の値が見つかったかどうかを判断できます。
上記のもう1つの利点は柔軟性です。 <=>の行の値が昇順であると通知されたため、<=>より大きい値が検出された場合、行の残りの部分は無関係です。どの変更を行うか、どこでそれを行うかを正確に知ることは簡単です。その新しい情報により現在の行を放棄できるため、内部の決定のみが影響を受け、次のようになります。
if (target < a[i][j] || SIZE <= ++j) { // can't be in row or fallen off end
...
古い<!> quot; counting <!> quot;を放棄する新しい言語(特に機能指向の言語)が増えています。ループ構造;単純にカウントするのではなく、ループの意味について考えることをお勧めします。
これまで見た中で最良の方法にはマクロとゴトが関係していますが、実際にはかなりnice(投稿へのリンクはPerlの話から始まりますが、最後の段落などではマクロを紹介しています)。
次のようなコードを記述できます。
named (LOOPS) for (i=1; i<10; i++) {
for (j=1; j<10; j++) {
for (j=1; j<10; j++) {
/* Process data[i][j][k] here */
if (data[i][j][k] < threshold) break(LOOPS);
}
}
}