1

次のようなコードがあるとします。

resource = allocateResource();
try { /* dangerous code here  */ }
finally { free(resource); }

ここで特定の言語について言及しているわけではありませんが、Java、C#、および C++ が良い例になると思います ( MSVC++ で__try/を使用していると仮定します)。__finally

これは例外セーフですか?

個人的には、これは例外セーフではないと思います。ブロックに入る前に例外が発生した場合はどうなるでしょうか? tryその後、リソースがリークします。

しかし、私はこれを十分に見てきましたが、何かが欠けていると思います... 私は? それとも、これは本当に危険ですか?


編集:

例外をスローすることについて質問しているわけではありませんが、その関数が返された後、割り当てられる前にallocateResource例外が発生する状況です。 resource

4

7 に答える 7

6

allocateResource が例外をスローすることについて質問しているわけではありませんが、その関数が返された後、リソースが割り当てられる前に例外が発生する状況です。

例外の安全性のこの側面を処理しようとすると、非常に厄介になります。特に、言語構造では、代入ステートメントの途中に finally ハンドラーをインストールできないためです。

これらすべての私の理論的根拠は、関数呼び出しの最後から変数への代入に到達できない場合、システムはすでにホースで覆われているということです。変数に代入できないときにメモリ リークが発生しても、誰が気にしますか?

于 2011-06-04T05:15:27.820 に答える
3

ポイントは、ブロックに例外をスローできるすべてのコードを含めることです。tryあなたの場合:

try
{
    resource = allocateResource();
    //...
}
finally { free(resource); }

そうでなければ - いいえ、もちろん安全ではありません。

于 2011-06-04T04:58:16.417 に答える
2

C# の場合、ThreadAbortException がリソースの割り当てと try ブロックの開始の間でスローされる可能性があるため、安全ではないと見なされます。このため、C#4 はusingブロックの展開を変更してリソース割り当てを try 内に移動し、finallyブロックは非表示のブール値 (または null に対するテスト — 正確には覚えていません) を使用して、割り当てが実際に行われたかどうかを判断します。 .

于 2011-06-04T05:10:10.500 に答える
1

allocateResource の書き方によって異なります。上記のスニペットを考えると、 allocateResource は次の 2 つの結果をもたらす可能性があります。1) リソースを割り当てて返す 2) 除外する (したがって、リソースを返さない)

したがって、allocateResourceスローする前に割り当てを内部的にリークしないことが確実な場合resource、そのメソッドはスローとリターンの両方を実行できないため、上記はリークしません。

于 2011-06-04T05:02:39.473 に答える
0

C#では、管理対象で参照されていないリソースは次回の実行時にガベージコレクションされるため、問題はありません。

于 2011-06-04T05:31:26.350 に答える
0

try{} ブロック内のコードのみが安全です。そして、すべての例外が正しくキャッチされた場合のみ。

もちろん、ブロックの外側のコードはそうではありません。それはまさに望ましい動作です。

また、finally{} ブロックのコードも例外をスローする可能性があるため、finally または catch ブロック内に try-catch ブロックを含める必要がある場合があることに注意してください。

例えば:

try {
    // your code here
} finally {
    try {
        // if the code in finally can throw another exception, you need to catch it inside it
    } catch (Exception e) {
       // probably not much to do besides telling why it failed
    }
} catch (Exception e) {
    try {
        // your error handling routine here
    } catch (Exception e) {
       // probably not much to do besides telling why it failed
    }
}
  • 割り当ての前に例外がスローされた場合、解放されるものは何もないため、リークするものはありません。
  • 割り当ての後、try/catch ブロックで例外が発生した場合、それは finally によって処理されます。
  • 割り当ての後、try/catch ブロックの前に例外が発生する可能性がある場合は、コードを再検討し、問題のある行をブロック内に移動する必要があります。
于 2011-06-04T05:02:05.893 に答える
0

あなたはあなた自身の質問に答えていると思います。allocateResourceリソースが変数に割り当てられる前に例外を割り当ててスローすると、リソースがリークし、ブロックでできることは何もありません。try/finallyこれは、ほとんどの言語 (Java や C# を含む) のブロックは、内部で使用するリソースについてtry/finally実際には認識していないためです。彼ら。

try/finallyしたがって、が有効であるためにallocateResourceは、どうにかしてアトミックであることを保証する必要があります。割り当てて変数に必ず割り当てるか、まったく割り当てずに失敗します。そのような保証がないため (特に予測不可能なスレッドの死を考慮すると)、try/finallyブロックは効果的に安全ではありません。

一部の言語は、リソースを認識しているusingorwith句のサポートを開始するため、それらを安全に閉じることができます (ただし、これはインタープリター/コンパイラー/ランタイムなどの実装に依存します)。

于 2011-06-04T05:22:47.483 に答える