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