したがって、C++ を使用して例外をネストする方法std::nested_exception
は次のとおりです。
void foo() {
try {
// code that might throw
std::ifstream file("nonexistent.file");
file.exceptions(std::ios_base::failbit);
}
catch(...) {
std::throw_with_nested(std::runtime_error("foo failed"));
}
}
しかし、この手法では、例外をネストしたいすべてのレベルで明示的な try/catch ブロックを使用します。これは控えめに言っても見苦しいものです。
Jon Kalbが「責任の取得は初期化である」と拡張した RAII は、明示的な try/catch ブロックを使用する代わりに、例外を処理するためのはるかにクリーンな方法です。RAII では、明示的な try/catch ブロックは、ユーザーにエラー メッセージを表示するなど、最終的に例外を処理するためにのみ主に使用されます。
上記のコードを見ると、入るfoo()
ことは、例外を報告しstd::runtime_error("foo failed")
、nested_exception 内に詳細をネストする責任を伴うと見なすことができるように思えます。RAII を使用してこの責任を負うことができれば、コードはよりきれいに見えます。
void foo() {
Throw_with_nested on_error("foo failed");
// code that might throw
std::ifstream file("nonexistent.file");
file.exceptions(std::ios_base::failbit);
}
ここで RAII 構文を使用して、明示的な try/catch ブロックを置き換える方法はありますか?
これを行うには、デストラクタが呼び出されたときに、デストラクタの呼び出しが例外によるものかどうかを確認し、そうであればその例外をネストし、巻き戻しが正常に続行されるように、ネストされた新しい例外をスローする型が必要です。それは次のようになります。
struct Throw_with_nested {
const char *msg;
Throw_with_nested(const char *error_message) : msg(error_message) {}
~Throw_with_nested() {
if (std::uncaught_exception()) {
std::throw_with_nested(std::runtime_error(msg));
}
}
};
ただしstd::throw_with_nested()
、「現在処理されている例外」がアクティブである必要があります。つまり、catch ブロックのコンテキスト内以外では機能しません。したがって、次のようなものが必要です。
~Throw_with_nested() {
if (std::uncaught_exception()) {
try {
rethrow_uncaught_exception();
}
catch(...) {
std::throw_with_nested(std::runtime_error(msg));
}
}
}
残念ながら、私の知る限りrethrow_uncaught_excpetion()
、C++ で定義されているようなものはありません。