この記事は、インテル® デベロッパー・ゾーンに公開されている「The Ultimate Question of Programming, Refactoring, and Everything」の日本語参考訳です。
37. do {…} while (…) 内の ‘continue’ 演算子に注意する
Haiku* プロジェクト (BeOS* の後継) から抜粋した以下のコードについて考えてみます。このコードにはエラーが含まれています。PVS-Studio アナライザーは、次の診断を出力します。
V696 The ‘continue’ operator will terminate ‘do { … } while (FALSE)’ loop because the condition is always false. (V696 ‘continue’ 演算子は、条件が常に false のため ‘do { … } while (FALSE)’ を終了します。)
do { .... if (appType.InitCheck() == B_OK && appType.GetAppHint(&hintRef) == B_OK && appRef == hintRef) { appType.SetAppHint(NULL); // try again continue; } .... } while (false);
説明
do-while ループ内の continue の動作は、一部のプログラマーが想定するものと異なります。continue に到達すると、常にループ終了条件がチェックされます。これについて、詳しく説明します。プログラマーが次のようなコードを記述したとします。
for (int i = 0; i < n; i++) { if (blabla(i)) continue; foo(); }
あるいは、次のようなコードをを記述したとします。
while (i < n) { if (blabla(i++)) continue; foo(); }
ほとんどのプログラマーは直観的に、continue に到達したら制御条件 (i < n) が評価 (または再評価) され、結果が ture の場合のみ次のループ反復が開始されると理解します。しかし、次のようなコードではどうでしょうか。
do { if (blabla(i++)) continue; foo(); } while (i < n);
この場合、continue の前に条件がないため、多くのプログラマーは直観的に、continue の直後に次のループ反復が開始されるかのように勘違いします。しかし、continue は通常どおりに動作し、制御条件が再評価されます。
この continue の理解の欠如がエラーにつながるかどうかは、運任せです。ただし、ループ条件が常に false の場合、上記のコード例のようにプログラマーが後続の反復で処理を行う予定だと、確実にエラーになります。上記のコード例では、コード中のコメント “// try again” から、プログラマーにその意図があることが分かります。もちろん、条件が常に false になるため、”again” はあり得ません。continue に到達するとループは終了します。
つまり、この do {…} while (false) 構造では、continue は break と同等です。
正しいコード
正しいコードの記述方法は多数あります。例えば、無限ループを作成して、continue でループの実行を継続し、break で終了します。
for (;;) { .... if (appType.InitCheck() == B_OK && appType.GetAppHint(&hintRef) == B_OK && appRef == hintRef) { appType.SetAppHint(NULL); // try again continue; } .... break; };
推奨事項
do { … } while (…) 内では continue を使用しないようにします。仮に、その仕組みを良く理解している場合であってもです。意図せずこのエラーを引き起こしたり、同僚がコードを正しく理解せずに間違ってコードを変更する可能性があるからです。くどいようですが、良いプログラマーとは、さまざまな言語のトリックを使いこなすことができる人ではなく、明確で分かりやすく、初心者でも理解できるコードを記述できる人です。
コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。