9

未処理の例外がコンストラクターからスローされるとどうなりますか? Java の場合、C++ の場合は? メモリリークは発生しますか?

4

8 に答える 8

6

Java の場合: 通常のメソッドから例外がスローされる場合と同様に、制御フローは呼び出し元に戻ります。メモリ リークなし (半分構築されたインスタンスは破棄され、ガベージ コレクションされます)

于 2012-12-21T01:17:24.817 に答える
2

少なくとも C++ では、未処理の例外は、main() に到達してプログラムを閉じるまで延々と続きます。解放されていないメモリは、オペレーティング システムによって処理されます。

それがあなたの質問に答えているかどうかわからない...?

したがって、基本的には、他の関数からスローされた場合と同じです。

于 2012-12-21T01:19:55.753 に答える
1

コンストラクター内で依存オブジェクトを作成すると、メモリ リークが発生する可能性があります。

どの言語/環境でも、これらの依存関係がそれらをクリーンアップしない外部エンティティによって参照されている場合、これによりリークが発生する可能性があります。

JAVA および C# では、依存関係が外部から参照されていない場合、これによってリークが発生することはありません。ガベージ コレクタは最終的にクリーンアップします。

C++ では、依存関係が外部から参照されていない場合、これにより確実にリークが発生します。

その他の可能性については、Jon の回答を参照してください: Java でコンストラクターは例外をスローできますか?

于 2013-09-09T14:18:52.430 に答える
0

追加する価値があります:

1)Javaは、「チェックされた」例外と「チェックされていない」例外を区別します

2)ほとんどのユーザー定義の例外は「チェック」する必要があります。つまり、コールチェーン内の各モジュールが、a)例外を処理するか、b)例外を「スロー」できることを明示的にマークしない限り、コードはコンパイルされません。

于 2012-12-21T01:24:15.243 に答える
-1

メモリリークが発生するかどうかは、コードの記述方法によって異なります。「適切な」コードを記述すれば、メモリリークが発生することはありません。しかし、これがひどくうまくいかないシナリオを思いつくことは完全に可能です。

コンストラクターがコンストラクターに何かを割り当てると、問題が発生する可能性があります。

一般的な解決策は、「2フェーズ構築」と呼ばれるものを使用することです。そのため、コンストラクター自体は非常に単純で、「間違いはありません」。オブジェクトが作成されたら、失敗する可能性のある方法でオブジェクトを埋めるメンバー関数を呼び出します。その後、例外を自由にスローできます。デストラクタがラインのある時点で実行されることが保証されている限り、すべてうまくいくはずです。「デストラクタ内の部分的に構築されたオブジェクト」に注意してください。ポインタがNULLの場合、またはデストラクタの途中で他の何かが構築されていない場合はどうなりますか。

[上記は、「メインに戻る前にどこかにハンドラーがあり、実際にはプログラム全体を中止する以外のことをしたい」という条件があります]。

于 2012-12-21T01:25:03.503 に答える
-1

状況は似ていますが、C++ と Java の両方の言語で異なります。

例外がスローされると、ハンドラーを探してスタックに戻ります。C++ または Java では、プログラムが見つからない可能性があるため、プログラムを最初まで巻き戻して終了します。Java には、何らかの種類の例外処理 (チェックされている場合) があることを強制するチェック例外の概念があります。C++ には例外指定の概念がありますが、これは非現実的 (設計が不適切) であり、使用すべきではありません。そのため、C++ ではすべての例外を「未チェック」と見なしてください。

例外が最終的にプログラムを終了させるか、それがスローされた場所のはるか上流のどこかでキャッチされるかどうかにかかわらず、それまでの巻き戻しプロセスが重要です。プログラムが終了した場合は、もちろん、OS がメモリを再利用するため、メモリ リークは発生しません。心配する必要があるのは次のとおりです。

  • 例外が最終的に上流のどこかで処理されると、アンワインド中にメモリ リークが発生します。と、
  • プログラムが終了した場合、OS によって再利用/元に戻されないため、リークする可能性のある他の種類のリソース (たとえば、保留中のデータベース操作、ネットワーク接続など)。

スタックの巻き戻しが発生すると、C++ では、簡単に言えば、完全に構築されたすべてのスタック バインド オブジェクト (構築中のオブジェクトのデータ メンバーまたは基本クラス インスタンスを含む) が即座に (つまり、決定論的に) 破棄されることが保証されます。それらが作成されたのとまったく逆の順序で。したがって、すべてのリソースがオブジェクトの構築/破棄 (「RAII」とも呼ばれます) に直接結び付けられている限り、正常に取得されたすべてのリソースが解放されるため、アンワインド プロセス中に (メモリまたはその他のリソースの) リークは発生しません (ただし、巻き戻し中にリソースを解放すると失敗するため、注意して処理する必要があります)。

Java では、「スタック」の巻き戻しは同じ方法で行われますが、オブジェクトをすぐに破棄するのではなく、オブジェクトを破棄 (つまり、ガベージ コレクションの対象) としてマークし、将来の不確定な時点で最終的に破棄する点が異なります。これにより、ガベージ コレクターがそのジョブを実行するのに十分な時間存続している限り、メモリ リークが発生しないことが保証されますが、プログラムが未処理の例外で終了した場合に保証されるかどうかはわかりません (ただし、その時点では問題ありません)。 . Java の主な問題は、他のリソースです。finallyこれらのリソースは、ブロックで解放する必要があります。finallyブロックはアンワインド中に実行されることが保証されていますが、もちろん、対応するブロックに割り当てられたリソースを解放するコードが含まれている必要があります。tryブロック。プログラマーが自分の仕事をしている限り、リソースがリークすることはありません。

例外がコンストラクターからスローされるという事実は、実際には大きな違いはありません。基本的なルールは、例外がスローされたときにリソースをリークしないための基本的なルールとまったく同じです。

  • C++ では、すべてのリソース (メモリなど) を 1つのオブジェクトに結び付けると、言語が残りのリソースをリークなしで保証します。これは、Resource Acquisition Is Initialization (RAII) イディオムです。
  • Javaでは、その単一のリソースを解放する独自のfinallyブロックを持つ独自のtryブロック内にすべての非メモリリソース取得を書き込むようにください。

どちらの場合も、リソースをクリーンに解放する必要があります (スローしない)。

于 2012-12-21T04:34:17.897 に答える