7

重複の可能性:
C++ でコンストラクターから例外がスローされた場合に初期化されたリソースをクリーンアップする方法

6 つのオブジェクトを作成していて、それらのオブジェクトが 5 つのオブジェクトを作成し、6 番目のオブジェクトの作成中に失敗した場合、コンストラクターで例外を処理するにはどうすればよいですか?

ありがとう。

4

3 に答える 3

3

通常の動作は、例外を伝播させることです。完全に構築された基本クラスとメンバーのデストラクタが呼び出されます。最初の 5 つのオブジェクトがメンバーである場合、それらは正しく破棄されます。

問題が発生する可能性がある唯一のケースは、話しているオブジェクトが動的に割り当てられている場合 (を使用new) です。その場合、最初に自問することは、なぜですか? オブジェクトを具体的なメンバーにせずに動的に割り当てるのはなぜですか? 私の経験では、そのような必要性は非常にまれですが、いくつかの特殊なケース (コンパイル ファイアウォール イディオムなど) を除いて、通常はクラス内に 1 つのオブジェクト (実装オブジェクトへのポインターなど) が存在します。 . このような場合、問題はありませnewん。そのオブジェクトの が失敗した場合、元に戻す必要のある操作は他に何も行われていないためです。

動的割り当てを実際に使用する必要があり、そのようなオブジェクトが複数あるという非常にまれなケースに遭遇した場合(たとえば、ポリモーフィックなサブオブジェクトが 2 つあるため)、各割り当てが確実に行われるようにする必要があります。ある種のサブオブジェクトにラップされています (スマート ポインターがうまく機能します)。最初のサブオブジェクトが正常に構築されると、コンストラクターが後で失敗すると、そのデストラクタが呼び出されます。

于 2012-10-04T09:43:31.607 に答える
1

コンストラクターで例外がスローされると、完全に構築されたすべてのサブオブジェクトが破棄されます。構築されたオブジェクトのデストラクタにそれらのリソースを監視させることは良い習慣であるため、これらのサブオブジェクトに対して何もする必要はありません。残っているのは、例外がスローされたときに現在実行中のコンストラクターの本体をクリーンアップすることです。ただし、これは他の関数のクリーンアップと同じです。

破壊順序は構築の逆であることに注意してください。つまり、本体のクリーンアップは、すべてのサブオブジェクトがまだ破棄されていないときに最初に開始されます。次にメンバーが破棄され、次に非仮想基本クラス、最後に仮想基本クラスが破棄されます。

于 2012-10-04T09:40:30.820 に答える
1

例外処理の「核心」は、デストラクタを介して事実上すべてをクリーンアップする必要があるということです。たとえば、オブジェクトを「新規作成」すると、「生の」ポインタが得られます。どこかで例外がスローされた場合は、この生のポインターが適切に「削除」されていることを確認する必要がありますが、初期化されていない生のポインターを削除しないようにしてください。

一方、そのポインターを std::unique_ptr に格納する場合は、何もする必要はありません。unique_ptr が破棄されると、オブジェクトが削除され、オブジェクトの破棄が自動的に行われます。unique_ptr がスコープ外になると、コンパイラはクリーンアップを呼び出します。もう「ああ、誰も実際にテストしていない珍しいパスをたどると、クリーンアップを忘れる」ことはありません)。

同じことがほぼすべてのリソースに適用できます。COM オブジェクトには "自動ポインタ" があり (たとえば、DirectX で使用されているように)、ほとんどのフレームワークはミューテックスをラップする "スコープ ロック" タイプのオブジェクトを提供する必要があります (そのため、オブジェクトが作成されたときにミューテックスをロックし、破壊されたときにロックを解除します)、さまざまな Windows ハンドルを処理する小さなラッパーを作成できます。

基本的に、すべてのクリーンアップをデストラクタに入れると、クリーンアップするためだけに「試行...キャッチ...再スロー」する必要がなくなります。また、「より大きな」オブジェクトのデストラクタは、事実上すべての「含まれる」オブジェクトがデストラクタによって自動的にクリーンアップされるため、多くの場合非常に単純です。

于 2012-10-04T10:57:59.037 に答える