[解決済み】デストラクタで例外を投げてはいけない場合、その中のエラーはどのように処理するのでしょうか?
質問
ほとんどの人がこう言います。 決して デストラクタで例外を発生させると、未定義の動作になります。Stroustrupは次のように指摘する。 ベクトルデストラクタは、すべての要素に対して明示的にデストラクタを呼び出します。これは、もし要素のデストラクタが投げたら、ベクターの破壊は失敗することを意味します... デストラクタから投げられる例外から保護する良い方法は本当にないので、ライブラリは要素のデストラクタが投げても何の保証もしません" (付録E3.2より) .
この記事 は、デストラクタを投げることは多かれ少なかれ問題ないと言っているようです。
デストラクタから投げると未定義の動作になる場合、デストラクタの途中で発生したエラーはどのように処理するのでしょうか?
クリーンアップ処理中にエラーが発生した場合、そのまま無視するのでしょうか?スタック上で処理できる可能性のあるエラーであっても、デストラクタ内で処理できない場合は、デストラクタの外で例外を投げるのが筋ではないでしょうか?
もちろん、この種のエラーはまれですが、あり得ることです。
解決方法は?
デストラクタから例外を投げるのは危険です。
他の例外が既に伝播している場合、アプリケーションは終了します。
#include <iostream>
class Bad
{
public:
// Added the noexcept(false) so the code keeps its original meaning.
// Post C++11 destructors are by default `noexcept(true)` and
// this will (by default) call terminate if an exception is
// escapes the destructor.
//
// But this example is designed to show that terminate is called
// if two exceptions are propagating at the same time.
~Bad() noexcept(false)
{
throw 1;
}
};
class Bad2
{
public:
~Bad2()
{
throw 1;
}
};
int main(int argc, char* argv[])
{
try
{
Bad bad;
}
catch(...)
{
std::cout << "Print This\n";
}
try
{
if (argc > 3)
{
Bad bad; // This destructor will throw an exception that escapes (see above)
throw 2; // But having two exceptions propagating at the
// same time causes terminate to be called.
}
else
{
Bad2 bad; // The exception in this destructor will
// cause terminate to be called.
}
}
catch(...)
{
std::cout << "Never print this\n";
}
}
これは基本的に煮詰まったものです。
危険なこと(つまり例外を投げる可能性のあること)は、(必ずしも直接でなく)パブリックメソッドで行うべきです。クラスのユーザーは、パブリックメソッドを使用し、潜在的な例外をキャッチすることで、これらの状況を処理できる可能性があります。
デストラクタは、これらのメソッドを呼び出してオブジェクトを終了させますが (ユーザーが明示的にそうしなかった場合)、スローされた例外はすべてキャッチされて (問題の修正を試みた後に) 取り除かれます。
つまり、事実上、ユーザーに責任を転嫁しているわけです。もしユーザーが例外を修正できる立場にあれば、適切な関数を手動で呼び出し、あらゆるエラーを処理するでしょう。オブジェクトのユーザが心配しないのであれば(オブジェクトは破棄されるので)、デストラクタに処理を任せることになります。
一例です。
std::fstream
close()メソッドは例外を投げる可能性があります。 デストラクタは、ファイルがオープンされている場合は close() を呼び出しますが、例外がデストラクタの外に伝搬しないようにします。
したがって、ファイルオブジェクトのユーザが、ファイルを閉じる際に発生する問題に対して特別な処理を行いたい場合、手動でclose()を呼び出し、あらゆる例外を処理することになります。一方、ファイルオブジェクトの使用者がファイルのクローズに関連する問題に対して特別な処理を行いたい場合は、デストラクタがその状況を処理することになります。
Scott Myersの著書「Effective C++"」にこの件に関する素晴らしい記事があります。
編集する
どうやら、"More Effective C++"にもあるようです。
項目11: デストラクタから例外が出ないようにする
関連
-
[解決済み】変数 '' を抽象型 '' と宣言できない。
-
[解決済み】システムが指定されたファイルを見つけられませんでした。
-
[解決済み】std::cin.getline( ) vs. std::cin
-
[解決済み】エラー。引数リストに一致するコンストラクタのインスタンスがない
-
[解決済み] 1ビットのセット、クリア、トグルはどのように行うのですか?
-
[解決済み] JUnit 4のテストで、ある例外が投げられたことをどのように断言しますか?
-
[解決済み] Pythonの関数が例外を投げるかどうかをテストするにはどうすればよいですか?
-
[解決済み] すべての例外をキャッチする `try`/`except` ブロックはどのように書けばよいですか?
-
[解決済み] 例外を正しく無視する方法
-
[解決済み] Javaにおける例外処理によるパフォーマンスへの影響とは?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】 != と =! の違いと例(C++の場合)
-
[解決済み] error: 'if' の前に unqualified-id を期待した。
-
[解決済み] クラスにデフォルトコンストラクタが存在しない。
-
[解決済み】#include<iostream>は存在するのですが、「識別子 "cout "は未定義です」というエラーが出ます。なぜですか?
-
[解決済み】クラスのコンストラクタへの未定義参照、.cppファイルの修正も含む
-
[解決済み】Visual Studioのデバッガーエラー。プログラムを開始できません 指定されたファイルが見つかりません
-
[解決済み】システムが指定されたファイルを見つけられませんでした。
-
[解決済み】Eclipse IDEでC++エラー「nullptrはこのスコープで宣言されていません」が発生する件
-
[解決済み] 現在のCまたはC++の標準文書はどこにありますか?
-
[解決済み】ifstreamを手動で閉じる必要がありますか?