サンプルの動作確認バージョン [GCC4.4/1.41.0] [VC9/1.41.0]
#include <iostream>
#include <string>
#include <stdexcept>
#include <boost/exception.hpp>
using namespace std;
// 例外クラスを boost::exception を継承して定義すると…
class MyException
: public boost::exception, public std::exception {};
// operator<< でエラー情報を追加できる
void h()
{
BOOST_THROW_EXCEPTION( MyException() ); // throw MyException() << ファイル名や行番号情報; の省略用マクロ
}
typedef boost::error_info<struct tag_errno, int> errno_info; // int型のエラー情報
void g()
{
try { h(); } catch( boost::exception& e )
{
e << errno_info(1234); // エラー情報を足して再throw
throw;
}
}
typedef boost::error_info<struct tag_errmsg, string> errmsg_info; // string型のエラー情報
void f()
{
try { g(); } catch( boost::exception& e )
{
e << errmsg_info("some bad thing happened"); // エラー情報を足して再throw
throw;
}
}
int main()
{
try { f(); } catch( boost::exception& e )
{
cout << diagnostic_information(e) << endl; // 表示
cout << *boost::get_error_info<errno_info>(e) << endl; // 個別に表示
}
}
Dynamic exception type: class MyException [struct boost::type<struct tag_errmsg>] = some bad thing happened [struct boost::type<struct tag_errno>] = 1234 [struct boost::type<struct boost::tag_throw_file>] = test.cpp [struct boost::type<struct boost::tag_throw_function>] = void __cdecl h(void) [struct boost::type<struct boost::tag_throw_line>] = 14 1234
例外に載っけるエラー情報は、レイヤー毎に詳細度が違ったりします。 Boost.Exception の公式のリファレンスに載っている例では、 「ファイル処理のエラーで、 例外発生部分ではファイルハンドルしかわからないのでファイル名の情報を 例外に入れられないが、1個上の関数ならファイル名も入れられる」 のようなのがあがっていました。 こういう場合に、レイヤー毎に何重にもラップした例外を放ったり、 あるいは全て文字列化して例外メッセージにつなげたりするのではなく、 ひとつのエラー情報伝達フレームワークで扱ってしまおう!というのがBoost.Exceptionです。
boost::expcetion を継承した例外クラスには、 error_info で囲んだ任意の型のエラー情報を載せることができます。 スレッドを超えて例外を飛ばす場合のデータの所有権管理などもうまいことやってくれる模様。 また、既存の例外オブジェクト/例外階層に潜り込んで情報載せを可能にする enable_error_info なども用意されています。