/****************************************************************************** Trick Library 'dagger' エラーハンドリングフレームワークヘッダファイル Copyright(C) 2007 Wraith. All rights reserved. Coded by Wraith in Nov 26, 2007. ******************************************************************************/ /////////////////////////////////////////////////////////////////////////////// // // ■ trickerr.h // http://tricklib.com/cxx/dagger/trickerr.h // // □ 関連ファイル // ありません。このファイルは単体で利用できます。 // // □ ライセンス情報 // http://tricklib.com/license.htm // #ifndef TRICKLIB_ERR_H #define TRICKLIB_ERR_H /////////////////////////////////////////////////////////////////////////////// // // デザインノート // // このフレームワークはファンクションインターフェイスに制限されないエラー // 情報ツリーを扱う為のものです。 // // 一般的にエラーを機能の呼び出し元に返す方法としては... // // ・戻り値あるいはOUT型引数 // ・グローバル変数 // ・例外送出 // // ...などと言った方法がありますが、戻り値の類ではファンクションインターフェ // イスに強く依存し同時にファンクションインターフェイスに制限を設けることに // なりさらにはコンストラクタ・デストラクタ及びコールバック関数などではしば // しばエラーの返却方法に困ります。 // // グローバル変数を使う方法は呼び出した機能のエラー情報がどのグローバル変数 // に格納されているのかわかりにくくまた機能毎にエラー返却の為のグローバル変 // 数を設けるのも馬鹿げています。 // // 戻り値やグローバル変数ではこの他にも無視していけない類のエラーが発生した // 場合で、且つ呼び出し側も無視するつもりのないエラーであってもチェック漏れ // によってうっかり無視してしまうというような問題もあります。 // // 例外送出では戻り値やグローバル変数のような問題はありませんが、例外送出を // 行った時点で必ず処理を中断しなければならなくなるという問題があります。 // // 一般的にエラーの返却方法としては上記に挙げた以外にも概ねエラー情報が唯一つ // のエラーしか扱えないという問題もあります。ある程度以上、複雑な処理ではエ // ラーがひとつ発生したからと言ってそこで即処理を中断するわけにはいきません。 // 実際、即処理を中断するつもりでもリソース解放やロールバック処理を行う必要 // に迫られまたその最中にさらにいくつかのエラーが発生することもありえます。 // // 関数呼び出しというものがツリーを形成する以上、エラー情報もツリーを形成さ // せるのがいいか悪いかは別にして少なくとも素直な設計と言えるでしょう。 // // 以上のことを踏まえこのエラーハンドリングフレームワークでは次のような特徴 // を持ちます。 // // ・エラー情報は(スレッド別に)ツリーを形成可能。 // ・エラーは例外処理と同様に"送出"することで呼び出し元に返す。 // ・送出されたエラーはエラーリスナーがキャッチする。 // ・エラーリスナーにキャッチされなかった場合を除きエラー送出では処理は中断 // されない。(キャッチされなかった場合、次項の例外送出により中断される場合 // がある) // ・エラーリスナーにキャッチされなかったり、いったんエラーリスナーにキャッ // チされたものの最終的には放置されたままになってしまったエラーを例外とし // て送出可能。 // ・エラー情報クラス及びエラーリスナークラスは自在にユーザ定義可能。 // // ...とまぁ、以上のコンセプトで作ってみたわけですが、この手のものは実際に // いろんなプログラムに適用してみないとその善し悪しはなかなか分からないもの // ですし、使いながらブラッシュアップしていく必要もあるのではないかと考えて // います。 /////////////////////////////////////////////////////////////////////////////// // // 使い方のメモ // // ・エラーフローモデル // //  1.error_thread_power error_thread_power_on(); //    ↑このオブジェクトを各スレッド毎に設置する。DLL などでスレッドと //     同等のパーシンスタンのローカルオブジェクトを設置できない場合は //     代わりに error_thread_init(); 呼び出しを行う。 // //  2.エラーをキャッチする為の error_listener_type(を継承した)クラスの //    オブジェクト作成する。 // //  3.エラーが発生したら error_element_type(を継承した)クラスのオブジェ //    クト作成する。 // //  4.「3」で作成したオブジェクトを throw_error() で送出する。 // //  5.「4」で送出されたオブジェクトが「2」で作成したオブジェクトの //    catch_error メンバー関数でキャッチできる。 // //  6.catch_error メンバー関数ではエラーを判別し、無視してもよいエラー //    ならエラーを消去( *error = NULL; )し、(ツリーを形成する為に)その //    時点では保留するなら pend_error() メンバー関数を呼び出す。消去 //    も保留もされなかったエラーは「スルー」されたものとして次のエラー //    リスナーに判断が委ねられる。 // //  7.全てのエラーリスナーにスルーされたエラーオブジェクトは no_catched() //    メンバー関数が呼び出される。→デフォルト no_catched() メンバーは //    throw_this() メンバー関数を呼び出し、自身を処理系組み込み throw で //    送出する。 // //  8.エラーリスナーに保留されているエラーは extract_pending_error() メ //    ンバー関数で放出しつつ throw_error() で送出するか、clear() メンバー //    関数で消去する。どちらも行われないままエラーリスナーのデストラクタ //    が呼び出されると保留されていたエラーは自動的に throw_error() で送出 //    される。 // //  9.「1」で error_thread_init() で初期化を行った場合スレッドの終了時 //    に error_thread_uninit(); で後片付けを行う。 // // ※シングルスレッドモデルの場合、「1」および「9」は不要です。 /////////////////////////////////////////////////////////////////////////////// // // マクロ定義 // // // ☆ユーザ定義 head_error_listener() 指定マクロ // // head_error_listener() 関数をユーザ定義する場合にこのマクロ指定してくだ // さい。このマクロが指定されるとこのヘッダファイルでは head_error_listener() // 関数が定義されなくなります。 // // コンパイル時に指定するのが面倒な場合は以下のコメント行を(コメントを解除 // して)有効にしてください。 // //#define TRICKLIB_ERR_USE_USER_HEAD_ERROR_LISTENER // // ☆スレッドモデル指定マクロ // // このモジュールをシングルスレッドで利用するのか、あるいはマルチスレッドで // 利用するのかを指定します。 // // どちらも指定されていない場合は _MT, __MT__ マクロを元に自動判別定義 // されます。 // // コンパイル時に指定するのが面倒な場合は以下のコメント行のどちらかを(コメン // トを解除して)有効にしてください。 // //#define TRICKLIB_ERR_SINGLE_THREAD //#define TRICKLIB_ERR_MULTI_THREAD #if !defined(TRICKLIB_ERR_SINGLE_THREAD) && !defined(TRICKLIB_ERR_MULTI_THREAD) # if defined(_MT) || defined(__MT__) # define TRICKLIB_ERR_MULTI_THREAD # else # define TRICKLIB_ERR_SINGLE_THREAD # endif #endif // // ☆スレッドローカルストレージ修飾指定マクロ // // このモジュールをマルチスレッドで利用する際に処理系組み込みのスレッド // ローカルストレージ機能を利用したい場合に指定します。 // // このマクロが定義されていなければ Windows API もしくは pthread を利用 // してスレッドローカルストレージを使用します。 // // コンパイル時に指定するのが面倒な場合は以下のコメント行のどちらかを(コメン // トを解除して)有効にしてください。 // // for vc //#define TRICKLIB_ERR_THREAD_LOCAL_STORAGE(type) __declspec(thread) type // for gcc //#define TRICKLIB_ERR_THREAD_LOCAL_STORAGE(type) __thread type #if defined(TRICKLIB_ERR_SINGLE_THREAD) && !defined(TRICKLIB_ERR_THREAD_LOCAL_STORAGE) # define TRICKLIB_ERR_THREAD_LOCAL_STORAGE(type) type #endif // // ☆ dynamic_cast_error 実装拒否指定マクロ // // dynamic_cast_error はメンバーテンプレートに依存しているのでメンバーテン // プレートに対応していない処理系ではこのマクロを指定して実装を拒否してく // ださい。 // // コンパイル時に指定するのが面倒な場合は以下のコメント行を(コメントを解除 // して)有効にしてください。 // //#define TRICKLIB_ERR_DISABLE_DINAMIC_CAST_ERROR // // ☆名前空間指定マクロ // // このモジュールが展開される名前空間を変更できます。 // // コンパイル時に指定するのが面倒な場合は以下のコメント行の名前空間をご希望の // 名前空間に修正した上で(コメントを解除して)有効にしてください。 // //#define TRICKLIB_ERR_NAMESPACE tricklib #if !defined(TRICKLIB_ERR_NAMESPACE) #define TRICKLIB_ERR_NAMESPACE tricklib #endif // // ☆エラー情報文字型指定マクロ // // このモジュールで使用する文字型を指定します。TRICKLIB_ERR_USE_CHAR もしくは // TRICKLIB_ERR_USE_WCHAR を定義してください。 // // どちらも指定されていない場合は _UNICODE, UNICODE マクロを元に自動判別定義 // されます。 // // コンパイル時に指定するのが面倒な場合は以下のコメント行のどちらかを(コメン // トを解除して)有効にしてください。 // //#define TRICKLIB_ERR_USE_CHAR //#define TRICKLIB_ERR_USE_WCHAR #if !defined(TRICKLIB_ERR_USE_CHAR) && !defined(TRICKLIB_ERR_USE_WCHAR) #if defined(_UNICODE) || defined(UNICODE) #define TRICKLIB_ERR_USE_WCHAR #else #define TRICKLIB_ERR_USE_CHAR #endif #endif // // ... // #if defined(TRICKLIB_ERR_USE_CHAR) # define TRICKLIB_ERR_CHAR_TYPE char # define TRICKLIB_ERR_T_CORE(X) X # define TRICKLIB_ERR_API_T(X) X##A #else # define TRICKLIB_ERR_CHAR_TYPE wchar_t # define TRICKLIB_ERR_T_CORE(X) L##X # define TRICKLIB_ERR_API_T(X) X##W #endif #define TRICKLIB_ERR_T(X) TRICKLIB_ERR_T_CORE(X) /////////////////////////////////////////////////////////////////////////////// // // defines // #if !defined(TRICKLIB_AVAILABLE_MEMBER_TEMPLATES) # if defined(__BORLANDC__) # if 540 <= __BORLANDC__ # define TRICKLIB_AVAILABLE_MEMBER_TEMPLATES # endif # endif // CodeWarrior ... # if defined(__MWERKS__) # if 0x2401 <= __MWERKS__ // 6.2以上 # define TRICKLIB_AVAILABLE_MEMBER_TEMPLATES # endif # endif // Microsoft ... # if defined(_MSC_VER) # endif // gcc/g++ ... # if defined(__GNUC__) # if 2 < __GNUC__ || 2 == __GNUC__ && 8 <= __GNUC_MINOR__ # define TRICKLIB_AVAILABLE_MEMBER_TEMPLATES # endif # endif // Digital Mars ... # if defined(__DMC__) # endif #endif #if !defined(TRICKLIB_ERR_MS_WINDOWS) #if defined(__WIN32__) || defined(_WIN32) # define TRICKLIB_ERR_MS_WINDOWS #endif #endif /////////////////////////////////////////////////////////////////////////////// // // includes // #include #include #include #if defined(TRICKLIB_ERR_MS_WINDOWS) # include #else # if defined(TRICKLIB_ERR_MULTI_THREAD) # include # endif #endif /////////////////////////////////////////////////////////////////////////////// // // ... // namespace TRICKLIB_ERR_NAMESPACE { // // エラー情報文字型 // typedef TRICKLIB_ERR_CHAR_TYPE error_char_type; /////////////////////////////////////////////////////////////////////////////// // // declare // // // スマートポインタ // // スマートポインタターゲット class err_smart_ptr_target; // スマートポインタシェル template class err_smart_ptr_shell; // // エラー情報型 // // 基本エラー情報型 class error_element_type; // エラーロケーション情報型 class error_location_type; // // エラーリスナー型 // // 基本エラーリスナー型 class error_listener_type; // // 関数 // // ヘッドエラーリスナー取得・設定関数 error_listener_type * * head_error_listener(); // エラー送出関数 void throw_error(error_element_type *error); /////////////////////////////////////////////////////////////////////////////// // // smart pointer // // // err_smart_ptr_target // class err_smart_ptr_target { private: int ref_count; public: err_smart_ptr_target() :ref_count(0) { } err_smart_ptr_target(const err_smart_ptr_target &) :ref_count(0) { } virtual ~err_smart_ptr_target() { } void ref_inc() { assert(0 <= ref_count); ++ref_count; assert(0 < ref_count); } void ref_dec() { assert(0 < ref_count); --ref_count; assert(0 <= ref_count); if (ref_count <= 0) { delete this; } } }; // // err_smart_ptr_shell // template class err_smart_ptr_shell { private: target_T * target; public: err_smart_ptr_shell(target_T * a_target = NULL) :target(a_target) { if (target) { target->err_smart_ptr_target::ref_inc(); } } err_smart_ptr_shell(const err_smart_ptr_shell & a) :target(a.target) { if (target) { target->err_smart_ptr_target::ref_inc(); } } ~err_smart_ptr_shell() { release(); } operator target_T * () { return target; } operator const target_T * () const { return target; } target_T * operator -> () { return target; } const target_T * operator -> () const { return target; } target_T & operator * () { return *target; } const target_T & operator * () const { return *target; } err_smart_ptr_shell & operator = (target_T * a_target) { release(); set(a_target); return *this; } err_smart_ptr_shell & operator = (const err_smart_ptr_shell & a) { release(); set(a.target); return *this; } void release() { if (target) { target->err_smart_ptr_target::ref_dec(); target = NULL; } } bool is_null() const { return !target; } operator bool () const { return target; } bool operator ! () const { return is_null(); } private: void set(target_T * a_target) { target = a_target; if (target) { target->err_smart_ptr_target::ref_inc(); } } }; /////////////////////////////////////////////////////////////////////////// // // err_thread_local_storage // #if defined(TRICKLIB_ERR_THREAD_LOCAL_STORAGE) template class err_thread_local_storage_base { private: static TRICKLIB_ERR_THREAD_LOCAL_STORAGE(target_T*) tls_ptr; protected: static void init() { } static target_T *get_target_storage() { return tls_ptr; } static void set_target_storage(target_T *target) { tls_ptr = target; } }; template TRICKLIB_ERR_THREAD_LOCAL_STORAGE(target_T*) err_thread_local_storage_base::tls_ptr = NULL; #elif defined(TRICKLIB_ERR_MS_WINDOWS) template class err_thread_local_storage_base { private: static volatile DWORD tls_handle; protected: static void init() { if (TLS_OUT_OF_INDEXES == tls_handle) { const error_char_type mutex_name[] = TRICKLIB_ERR_T("TrickLibrary::TLS::Init"); // 直接文字列リテラルを CreateMutex の引数に使用すると ERROR_NOACCESS になる場合があるのでスタックを経由する。 HANDLE mutex_handle = TRICKLIB_ERR_API_T(CreateMutex)(NULL, TRUE, mutex_name); assert(NULL != mutex_handle); WaitForSingleObject(mutex_handle, INFINITE); if (TLS_OUT_OF_INDEXES == tls_handle) { tls_handle = TlsAlloc(); assert(NULL != mutex_handle); } CloseHandle(mutex_handle); assert(TLS_OUT_OF_INDEXES != tls_handle); } } static target_T *get_target_storage() { if (TLS_OUT_OF_INDEXES == tls_handle) { return (target_T *)NULL; } else { return (target_T *)TlsGetValue(tls_handle); } } static void set_target_storage(target_T *target) { assert(TLS_OUT_OF_INDEXES != tls_handle); if (TLS_OUT_OF_INDEXES != tls_handle) { TlsSetValue(tls_handle, target); } } }; template volatile DWORD err_thread_local_storage_base::tls_handle = TLS_OUT_OF_INDEXES; #else template class err_thread_local_storage_base { static pthread_key_t tls_handle; static pthread_once_t tls_handle_init_once; static void tls_handle_destroy(void * tls_handle) { // 実際にはここに到達される前に削除されていなければならない。 assert(NULL == tls_handle); delete (target_T*)tls_handle; } static void tls_handle_alloc() { pthread_key_create(&tls_handle, tls_handle_destroy); } public: static void init() { pthread_once(&tls_handle_init_once, tls_handle_alloc); } static target_T *get_target_storage() { if (0 == tls_handle) // 0 で問題なさげだが、保証はなし。 { return (target_T *)NULL; } else { return (target_T *)pthread_getspecific(tls_handle); } } static void set_target_storage(target_T *target) { pthread_setspecific(tls_handle, target); } }; template pthread_key_t err_thread_local_storage_base::tls_handle = 0; // 0 で問題なさげだが、保証はなし。 template pthread_once_t err_thread_local_storage_base::tls_handle_init_once = PTHREAD_ONCE_INIT; #endif template class err_thread_local_storage :public err_thread_local_storage_base { typedef err_thread_local_storage_base base_type; public: err_thread_local_storage(target_T *new_target) { init(new_target); } ~err_thread_local_storage() { uninit(); } static void init(target_T *new_target) { base_type::init(); base_type::set_target_storage(new_target); } static void uninit() { target_T *target = base_type::get_target_storage(); if (target) { delete target; base_type::set_target_storage(NULL); } } static target_T *get_target() { return base_type::get_target_storage(); } }; /////////////////////////////////////////////////////////////////////////////// // // エラー情報 // // // エラー情報型 // typedef err_smart_ptr_shell error_type; // // 基本エラー情報型 // #if defined(__BORLANDC__) # pragma warn -8027 #endif class error_element_type :public err_smart_ptr_target { // ユーザ独自のエラー情報型を定義する際にこのクラスを継承させます。 public: const error_char_type * message; error_type children; error_type next; error_element_type ( const error_type & a_children ) :message(TRICKLIB_ERR_T("unnamed error")) ,children(a_children) ,next(NULL) { } error_element_type ( const error_char_type * a_message = TRICKLIB_ERR_T("unnamed error"), const error_type & a_children = NULL ) :message(a_message), children(a_children), next(NULL) { } error_element_type(const error_element_type & a) :message(a.message), children(a.children), next(a.next) { } public: virtual ~error_element_type() { } virtual void no_catched() { // エラーがスルーされちゃった場合の処理をこのメソッドで行う。 // 具体的には無視されちゃいけないエラーの場合に throw_this() を行ったり、 // エラーログの出力行ったりする。 throw_this(); } void throw_this() { // this をそのままスルーするとその this を保持しているスマートポインタ // が全て例外処理の巻き戻しにより破棄され、最後のスマートポインタが // 破棄された際にその this も破棄されしまい、catch されるのは無効な // アドレスとなるので throw する際にはスマートポインタ(error_type)で // ラップして throw を行う。 throw error_type(this); } }; #if defined(__BORLANDC__) # pragma warn .8027 #endif // // エラー情報派生型用 dynamic_cast // #if defined(TRICKLIB_AVAILABLE_MEMBER_TEMPLATES) class dynamic_cast_error { error_element_type * error; public: dynamic_cast_error(error_element_type * a_error) :error(a_error) { } template operator T * () { return dynamic_cast(error); } }; #endif // // エラーメッセージ情報型 // class error_message_type :public error_element_type { public: typedef std::basic_string error_string_type; private: error_string_type message_holder; public: error_message_type ( const error_string_type & a_message, const error_type & a_children = NULL ) :error_element_type(a_children) { set_message(a_message); } error_message_type ( const error_type & a_children = NULL ) :error_element_type(a_children) { } void set_message(const error_string_type & a_message) { message_holder = a_message; message = message_holder.c_str(); } }; #if defined(TRICKLIB_ERR_MS_WINDOWS) // // Win32エラー情報型 // class win32_error_type :public error_message_type { DWORD error_code; public: win32_error_type ( DWORD a_error_code = GetLastError(), const error_type & a_children = NULL ) :error_message_type(TRICKLIB_ERR_API_T(get_msg)(a_error_code), a_children), error_code(a_error_code) { } DWORD get_error_code() const { return error_code; } void set_error_code(DWORD a_error_code) { error_code = a_error_code; } static const std::string get_msgA(DWORD error_code) { LPVOID message_buffer; FormatMessageA ( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&message_buffer, 0, NULL ); const std::string result = (const char *)message_buffer; LocalFree(message_buffer); return result; } static const std::wstring get_msgW(DWORD error_code) { LPVOID message_buffer; FormatMessageW ( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&message_buffer, 0, NULL ); const std::wstring result = (const wchar_t *)message_buffer; LocalFree(message_buffer); return result; } }; #endif // // エラーロケーション情報型 // class error_location_type { // このクラスはユーザの利便性を考えて定義されているものでこのモジュール // の他のクラスおよび関数では一切使用されていません。 // ユーザ定義のエラー情報型に継承させるなどして使用してください。 // // □継承ユーティリティ // // http://tricklib.com/cxx/dagger/inherit.h // 上記アドレスの継承ユーティリティを使用すると... // // throw_error // ( // new_dimorph // ( // error_element_type("someone error"), // error_location_type(__FILE__, __LINE__) // ) // ); // // ...のような形でお手軽にこのロケーション情報を付加することができます。 // また、エラー情報に付加されたロケーション情報は以下のような形で利用 // できます。 // // error_listener_type error_listener; // ... // error_type error = error_listener.get_pending_error(); // if (error) // { // error_location_type * location = dynamic_cast_error(error); // if (NULL == location) // { // fprintf(stderr, "%s\n", error->message); // } // else // { // fprintf(stderr, "%s@%s#%d\n", error->message, location->file, location->line); // } // } public: const error_char_type * file; int line; error_location_type ( const error_char_type * a_file = TRICKLIB_ERR_T("unknown file"), int a_line = 0 ) :file(a_file) ,line(a_line) { } }; /////////////////////////////////////////////////////////////////////////////// // // 基本エラーリスナー型 // #if defined(__BORLANDC__) # pragma warn -8027 #endif class error_listener_type { protected: // ユーザ独自のエラーリスナー型を定義する際にこのクラスを継承させます。 friend void throw_error(error_element_type * error); error_listener_type * next; error_type pending_error; error_type * error_junction; public: error_listener_type() :pending_error(NULL) ,error_junction(&pending_error) { listener_on(); } virtual ~error_listener_type() { close(); } // 閉鎖 virtual void close() { // この関数は主にデストラクタ内から安全に例外を送出できない処理系を // 利用している際にデストラクタが呼び出される前に明示的に閉鎖処理を // 行う為のものです。 if (is_listener_on()) { listener_off(); } // 未処理のエラーが残っていれば再送出を行う。 if (pending_error) { throw_error(extract_pending_error()); } } protected: error_listener_type * * find_listener_junction() { error_listener_type * * head_listener = head_error_listener(); assert(NULL != head_listener); for(error_listener_type * * i = head_listener; *i; *i = (*i)->next) { if (this == *i) { return i; } } return head_listener; } bool is_listener_on(error_listener_type * * listener_junction) { return this == *listener_junction; } public: // ... bool is_listener_on() { return is_listener_on(find_listener_junction()); } // 活性化 error_listener_type & listener_on() { error_listener_type * * listener_junction = find_listener_junction(); if (!is_listener_on(listener_junction)) { this->next = *listener_junction; *listener_junction = this; } return *this; } // 不活性化 error_listener_type & listener_off() { error_listener_type * * listener_junction = find_listener_junction(); if (is_listener_on(listener_junction)) { *listener_junction = this->next; this->next = NULL; } return *this; } // エラー送出イベントの応答(エラーのキャッチ) virtual void catch_error(error_type * error) { assert(NULL != error); // NULL を catch_error の引数として渡してはいけない // エラーを保留 pend_error(error); // エラーを消去する場合は error->release(); を行う。 } // エラー情報の保留 void pend_error(error_type * error) { assert(NULL != error); // NULL を pend_error の引数として渡してはいけない *error_junction = *error; error_junction = &((*error_junction)->next); error->release(); } // 保留しているエラー情報のクリア void clear() { pending_error.release(); error_junction = &pending_error; } // 保留しているエラー情報の取得 error_type get_pending_error() { return pending_error; } // 保留しているエラー情報の放出 error_type extract_pending_error() { // この関数は通常以下のような形でエラー情報ツリーを形成するのに // 使用されます。 // // error_listener_type error_listener; // ... // throw_error // ( // new error_element_type // ( // "someone error", // error_listener.listener_off().extract_pending_error() // ) // ); error_type result = pending_error; clear(); return result; } // エラー状況のチェック bool has_error() const { return pending_error; } }; #if defined(__BORLANDC__) # pragma warn .8027 #endif /////////////////////////////////////////////////////////////////////////////// // // ヘッドエラーリスナー管理関数 // #if defined(__BORLANDC__) # pragma warn -8027 #endif #if !defined(TRICKLIB_ERR_USE_USER_HEAD_ERROR_LISTENER) // // (スレッドローカル)ヘッドエラーリスナーの初期化コード // inline void error_thread_init() { // マルチスレッド環境下でこのモジュールを利用する際は各スレッドで最初に // この関数を呼び出して初期化を行ってください。ヘッドエラーリスナー管理 // オブジェクトを設置している場合は不要です。 #if !defined(TRICKLIB_ERR_SINGLE_THREAD) err_thread_local_storage::init(new error_listener_type * (NULL)); #endif } // // (スレッドローカル)ヘッドエラーリスナーの解放コード // inline void error_thread_uninit() { // マルチスレッド環境下でこのモジュールを利用する際は各スレッドの最後に // この関数を呼び出して解放を行ってください。ヘッドエラーリスナー管理 // オブジェクトを設置している場合は不要です。 #if !defined(TRICKLIB_ERR_SINGLE_THREAD) err_thread_local_storage::uninit(); #endif } // // (スレッドローカル)ヘッドエラーリスナー管理オブジェクト // class error_thread_power { public: error_thread_power() { // (スレッドローカル)ヘッドエラーリスナーの初期化コード error_thread_init(); } ~error_thread_power() { // (スレッドローカル)ヘッドエラーリスナーの解放コード error_thread_uninit(); } }; // // ヘッドエラーリスナーポインタ取得関数 // inline error_listener_type * * head_error_listener() { #if defined(TRICKLIB_ERR_SINGLE_THREAD) static TRICKLIB_ERR_THREAD_LOCAL_STORAGE(error_listener_type *) head_listener = NULL; return &head_listener; #else return err_thread_local_storage::get_target(); #endif } #endif #if defined(__BORLANDC__) # pragma warn .8027 #endif /////////////////////////////////////////////////////////////////////////////// // // エラー送出関数 // #if defined(__BORLANDC__) # pragma warn -8027 #endif inline void throw_error(error_element_type * a_error) { assert(NULL != a_error); // NULL を throw_error の引数として渡してはいけない // ...が、この関数の引数は new したばかりのエラー情報オブジェクトが // そのまま渡されるのが常なので、将来的にはメモリー不足の状況を想定 // した修正を施す予定ではいるが、コードが煩雑になるので当面はそこま // ではやらない。 error_type error = a_error; // // ヘッドエラーリスナーから順番にエラー送出イベントを通知 // for ( error_listener_type * listener = *head_error_listener(); listener; listener = listener->next ) { listener->catch_error(&error); if (!error) { // エラーがキャッチされたので処理を終了 return; } } // エラーがキャッチされなかった error->no_catched(); } #if defined(__BORLANDC__) # pragma warn .8027 #endif }; #endif // TRICKLIB_ERR_H /****************************************************************************** □■□■ Wraith the Trickster □■□■ ■□■□ 〜I'll go with heaven's advantage and fool's wisdom.〜 ■□■□ ******************************************************************************/