2012-04-02 11 views
2

boost::copy_exceptionを使用して例外をexception_ptrにコピーすると、タイプ情報が失われます。次のコードを見てみましょう:このことからboost :: copy_exceptionを使用しているときに型情報が失われるのはなぜですか?

try { 
    throw std::runtime_error("something"); 
} catch (exception& e) { 
    ptr = boost::copy_exception(e); 
} 
if (ptr) { 
    try { 
     boost::rethrow_exception(ptr); 
    } catch (std::exception& e) { 
     cout << e.what() << endl; 
     cout << boost::diagnostic_information(e) << endl; 
    } 
} 

、私は次のような出力が得られます。

N5boost16exception_detail10clone_implISt9exceptionEE 
Dynamic exception type: boost::exception_detail::clone_impl<std::exception> 
std::exception::what: N5boost16exception_detail10clone_implISt9exceptionEE 

だから、基本的boost::copy_exceptionは静的にそれが得た引数をコピーしました。

代わりにboost::enable_current_exceptionで例外をスローすると、この問題は解決されます。

try { 
    throw boost::enable_current_exception(std::runtime_error("something")); 
} catch (...) { 
    ptr = boost::current_exception(); 
} 
if (ptr) { 
    try { 
     boost::rethrow_exception(ptr); 
    } catch (std::exception& e) { 
     cout << e.what() << endl; 
     cout << boost::diagnostic_information(e) << endl; 
    } 
} 

これに伴う問題は時々例外がboost::enable_current_exceptionを使用していないライブラリによってスローされていることです。この場合、可能な例外の種類ごとに1つずつキャッチすることを除いて、例外をexception_ptrに入れ、それぞれにboost::copy_exceptionを使用する方法はありますか?

+0

私は実際にはboost例外をよく知っていませんが、型を保持しながら現在の例外を再びスローする 'catch'ブロックで単純な' throw; 'を試しましたか? – Asha

+0

あなたはおそらく[スライス](http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c)の問題に苦しんでいるでしょう。 – enobayram

答えて

4

これは仕様です。分析は正しいです。つまり、動的な種類ではなく静的な種類が使用されます。実際、この驚きを避けるために、boost::copy_exceptionstd::make_exception_ptrとなり、C++ 11につながったプロセス中になりました。そうすれば、current_exception(BoostバージョンかC++ 11かにかかわらず)が、現在の例外を正しくキャプチャするために使用する正しいものであることが明確になります。 Boost.Exceptionが有効な例外をコードに使用することについては、BOOST_THROW_EXCEPTION、または少なくともboost::throw_exceptionを使用することを強くお勧めします。

サードパーティのコードに関しては、既に言及したもの以外の解決策や他の道徳的に同等のものはありません(dynamic_cast-例外タイプの階層を構成するさまざまなリーフクラス、または虐待)。

この点で例外処理は、1つ以上の多態型の階層を扱う場合と同じです。この場合、操作しようとしているのはバーチャルコピー(クローンとも呼ばれます)です。 (throw e;の代わりに例えばBOOST_THROW_EXCEPTION(e);を使用する場合のように)サポートするか、またはあなたは痛みを伴って継承ツリーを処理します。その痛みを少なくとも1つのサイトにリファクタリングすることができます。たとえば、次のようになります。

try { 
    third_party_api(); 
} catch(...) { 
    ptr = catch_exceptions_from_api(); 
} 
関連する問題