[OK]を世紀の質問:)次のような状況でgotoを使用してもよろしいですか?
あなたが言うか何かを考える前に、私はこの非常にトピックに関する同様の質問のカップルを読んだことを教えてみましょうが、私は私のための明確な解決策を見つけられませんでした問題。私のケースは具体的であり、システムプログラマのための典型的なものです。
私はこの状況が非常によくあります。私は、本当に誰もがそれが悪いと叫んでいる理由を知っていない、おそらく嫌いだ。しかし、今まで私は自分のシナリオに対してより良い解決策を見つけることはできませんでした。私がやっているやり方は現在、gotoの使用よりも醜いかもしれません。
ここに私のケースです:私はWindowsアプリケーションの開発にはC++(Visual C++)を使用しており、私のルーチンではかなりの頻度でAPIを使用しています。だから、各APIの後、私はそれがなかった場合、それが成功したかどうかを確認し、私の機能を中断する必要が
int MyMemberFunction()
{
// Some code... //
if (!SomeApi())
{
// Cleanup code... //
return -1;
}
// Some code... //
if (!SomeOtherApi())
{
// Cleanup code... //
return -2;
}
// Some more code... //
if (!AnotherApi())
{
// Cleanup code... //
return -3;
}
// More code here... //
return 0; // Success
}
:次のような状況を仮定します。このために、私は// Cleanup code... //
の束を使用します。しばしばかなり複製され、その後にreturn
という文が続きます。この機能は、例えば10個のタスク(例えば10個のApisを使用する)を実行し、タスク#6が失敗した場合、以前のタスクによって作成されたリソースをクリーンアップする必要がある。クリーンアップは関数自体で行う必要があるため、例外処理は使用できません。また、このような状況で、いかに多くの話題のRAIIが私を助けてくれるのか分かりません。
私が考えた唯一のやり方は、gotoを使用して、そのようなすべての失敗事例から機能の最後に配置されたクリーンアップラベルにジャンプすることです。
これを実行する方法はありますか?このような状況では、gotoを使うのは悪い習慣と思われますか?何をしたらいいですか?このような状況は、私にとって(そして私のようなシステムプログラマにとっては)典型的なことです。
P .:リソースをクリーンアップする必要があるリソースは、種類が異なります。閉鎖を必要とするメモリの割り当て、さまざまなシステムオブジェクトハンドルなどがあるかもしれません
UPDATE:
私は、人々はまだ私は(おそらく私がひどく説明しています)望んで取得していないと思います。私は擬似コードは十分なはずと思ったが、ここでは実用的な例である:
私はCreateFileを持つ2つのファイルを開きます。この手順が失敗した場合:既に開いているファイルハンドルがあればそれをクリーンアップする必要があります。私は後であるファイルの一部を読んで、別のファイルに書き込む。
私はSetFilePointerを使用して、最初のファイルに読み取りポインタを配置します。この手順が失敗した場合:前の手順で開いたハンドルを閉じる必要があります。
私はGetFileSizeを使用してターゲットファイルサイズを取得します。 apiが失敗した場合、またはファイルサイズが異常な場合は、前の手順と同様にクリーンアップを行う必要があります。
最初のファイルから読み込むために指定されたサイズのバッファを割り当てます。メモリの割り当てに失敗した場合は、ファイルハンドルをもう一度閉じる必要があります。
最初のファイルから読み込むにはReadFileを使用する必要があります。これに失敗した場合は、バッファメモリを解放し、ファイルハンドルをクローズする必要があります。
私はSetFilePointerを使用して、2番目のファイルに書き込みポインタを配置します。これに失敗した場合は、同じクリーンアップを実行する必要があります。
2番目のファイルに書き込むためにWriteFileを使用する必要があります。これはまた、BLA-BLA-BLA ...
を失敗した場合、私はクリティカルセクションでこの機能を守る、と私は関数の先頭にEnterCriticalSection
を呼び出した後、私はすべてのreturn
前LeaveCriticalSection
を呼び出すことがあるとしステートメント。
これは非常に単純化された例です。より多くのリソースとクリーンアップが実行される可能性がありますが、ほとんど同じですが、時には少し異なりますが、どのステップが失敗したかに基づいています。しかし、この例の中で話しましょう:私はここでRAIIを使うことができますか?
[それはどれくらい悪いことができますか?](ただし、真剣に、*より読みやすいコード*を作成すると悪くはありません。 ) –
クリーンアップコードは共通ですか、クリーンアップコードはその機能にどれくらい手が届くかによって決まりますか? – Corbin
gotoを回避する方法の1つは、intをスローしてキャッチすることです。 – QuentinUK