以前、C ++で例外をチェーンする方法について質問しましたが、その回答の1つは、それを実行する方法に対する気の利いた解決策を提供しました。問題は、私がコードを理解していないことです。コメントでこの種の議論をしようとするのは、あまりにも面倒です。だから私は完全に新しい質問を始める方が良いと思いました。
コードは以下に含まれており、取得できない各セクションに明確にマークを付けています。私が理解していないことの説明は、コードの下に含まれています。コードはPotatoswatterによって書かれました。
コード
struct exception_data { // abstract base class; may contain anything
virtual ~exception_data() {}
};
struct chained_exception : std::exception {
chained_exception( std::string const &s, exception_data *d = NULL )
: data(d), descr(s) {
try {
link = new chained_exception;
// ----------------------------------------------------------------
// How does this work (section 1)?
throw;
// ----------------------------------------------------------------
} catch ( chained_exception &prev ) {
// ----------------------------------------------------------------
// How does this work (section 2)?
swap( *link, prev );
// ----------------------------------------------------------------
} // catch std::bad_alloc somehow...
}
friend void swap( chained_exception &lhs, chained_exception &rhs ) {
std::swap( lhs.link, rhs.link );
std::swap( lhs.data, rhs.data );
swap( lhs.descr, rhs.descr );
}
virtual char const *what() const throw() { return descr.c_str(); }
virtual ~chained_exception() throw() {
// --------------------------------------------------------------------
// How does this work (section 3)?
if ( link && link->link ) delete link; // do not delete terminator
// --------------------------------------------------------------------
delete data;
}
chained_exception *link; // always on heap
exception_data *data; // always on heap
std::string descr; // keeps data on heap
private:
chained_exception() : link(), data() {}
friend int main();
};
void f() {
try {
throw chained_exception( "humbug!" );
} catch ( std::exception & ) {
try {
throw chained_exception( "bah" );
} catch ( chained_exception &e ) {
chained_exception *ep = &e;
for ( chained_exception *ep = &e; ep->link; ep = ep->link ) {
// Print ep->what() to std::cerr
}
}
}
try {
throw chained_exception( "meh!" );
} catch ( chained_exception &e ) {
for ( chained_exception *ep = &e; ep->link; ep = ep->link ) {
// Print ep->what() to std::cerr
}
}
}
int main() try {
// ------------------------------------------------------------------------
// How does this work (section 4)?
throw chained_exception(); // create dummy end-of-chain
// ------------------------------------------------------------------------
} catch( chained_exception & ) {
// body of main goes here
f();
}
コードを実行すると、次の出力が得られます。
bah
humbug!
meh!
わからないこと
throw;
ブロック内try
:これは今まで見たことがありません。throw;
私が有効だと思った唯一の場所は、catch
捕らえられたものを投げ直すためのブロックの内側でした。では、これは何をするのでしょうか?一部のデバッグでは、スローされた例外が以前にスローされたものであることが明らかに示されていますが、それは完全に異なるtry
ブロック内にありました。struct
実際、それは宣言の外でさえありました!フィールドの交換:なぜ例外フィールドを交換する必要があるのですか?ポインタをコピーするだけで十分ではないでしょうか。これは、フィールドが指す構造がヒープから時期尚早に削除されるのを防ぐためですか?
チェック
link
とlink
'sリンク:link
そうでないチェックは理解できますが(ポインタをNULL
削除しても効果はありませんが)、なぜ'sリンクをチェックする必要があるのでしょうか。NULL
link
ダミー例外をスローする:なぜこのダミーが必要なのですか?投げられたが、その後落とされた。チェーンの終わりとしてこれが必要なのはなぜですか?