だから私の質問はこれです-デストラクタからスローすると未定義の動作が発生する場合、デストラクタ中に発生するエラーをどのように処理しますか?
主な問題は次のとおりです。失敗することはできません。結局、失敗に失敗するとはどういう意味ですか?データベースへのトランザクションのコミットが失敗し、失敗しない (ロールバックできない) 場合、データの整合性はどうなりますか?
デストラクタは通常のパスと例外的な (失敗した) パスの両方に対して呼び出されるため、それら自体が失敗することはありません。
これは概念的に難しい問題ですが、多くの場合、解決策は失敗が失敗しないようにする方法を見つけることです。たとえば、データベースは、外部データ構造またはファイルにコミットする前に変更を書き込む場合があります。トランザクションが失敗した場合、ファイル/データ構造は破棄できます。その場合、確実に行う必要があるのは、その外部構造/ファイルからの変更を、失敗することのないアトミック トランザクションにコミットすることだけです。
実用的な解決策は、おそらく失敗時に失敗する可能性が天文学的にありそうもないことを確認することです。
私にとって最も適切な解決策は、クリーンアップ ロジックが失敗しないように非クリーンアップ ロジックを記述することです。たとえば、既存のデータ構造をクリーンアップするために新しいデータ構造を作成したい場合は、その補助構造を事前に作成して、デストラクタ内で作成する必要がないようにすることができます。
確かに、これは言うは易く行うは難しですが、私が考える唯一の適切な方法です。通常の実行パスと例外的な実行パスの別々のデストラクタ ロジックを記述する機能が必要だと思うことがあります。これは、デストラクタが両方を処理しようとすることで、2 倍の責任を負っているように感じることがあるためです (例としては、明示的な却下を必要とするスコープ ガードがあります)。 ; 例外的な破壊パスと非例外的な破壊パスを区別できる場合、これは必要ありません)。
それでも、究極の問題は、失敗することはできないということであり、すべてのケースで完全に解決するのは難しい概念設計の問題です。多数の小さなオブジェクトが相互に作用する複雑な制御構造に巻き込まれすぎず、代わりに少しかさばる方法で設計をモデル化すると、簡単になります (例: 粒子全体を破壊するデストラクタを備えた粒子システム)。システムであり、パーティクルごとに個別の非自明なデストラクタではありません)。この種のより粗いレベルで設計をモデル化すると、処理する重要なデストラクタが少なくなり、多くの場合、デストラクタが失敗しないようにするために必要なメモリ/処理のオーバーヘッドを許容できます。
そして、これは当然、デストラクタの使用頻度を減らす最も簡単な解決策の 1 つです。上記のパーティクルの例では、おそらくパーティクルを破棄/削除する際に、何らかの理由で失敗する可能性があるいくつかのことを行う必要があります。その場合、例外的なパスで実行される可能性のあるパーティクルの dtor を介してそのようなロジックを呼び出す代わりに、パーティクル システムがパーティクルを削除するときにすべてをパーティクル システムで実行することができます。パーティクルの削除は、例外的でないパスで常に実行される場合があります。システムが破壊された場合、おそらくすべてのパーティクルをパージすることができ、失敗する可能性のある個々のパーティクル除去ロジックに煩わされることはありませんが、失敗する可能性のあるロジックは、パーティクル システムの通常の実行中に 1 つまたは複数のパーティクルを除去するときにのみ実行されます。
自明ではないデストラクタを使用して多くの小さなオブジェクトを処理することを避けると、そのような解決策がしばしば発生します。例外安全であることがほとんど不可能に思える混乱に巻き込まれる可能性があるのは、すべてが重要な dtor を持つ多くの小さなオブジェクトに巻き込まれる場合です。
それを指定するもの (基本クラスの noexcept 仕様を継承する必要がある仮想関数を含む) がスローされる可能性のあるものを呼び出そうとした場合に、nothrow/noexcept が実際にコンパイラ エラーに変換されると、非常に役立ちます。このようにして、スローされる可能性のあるデストラクタを実際に誤って記述した場合、コンパイル時にこれらすべてのものをキャッチできます。