
| 
\n | [ トップページ ] [ ____CommandPrompt ]
[ ____JScript ]
[ ____MySQL ]
[ ____Cygwin ]
[ ____Java ]
[ ____Emacs ]
[ ____Make ]
[ ____Perl ]
[ ____Python ]
[ ____OpenGL ]
[ ____C# ]
[ ____StyleSheet ]
[ ____C++ ]
[ ____Winsock ]
[ ____Thread ]
[ ____VisualStudio ]
[ ____C ]
[ ____Win32API ]
[ ____Lua ]
[ ____PhotoShop ]
 ヘッダ検索
 
 
 ■ 例外(Exception)
   C++ にはエラーを処理するための機構として例外というものが用意されている。
   C スタイルの関数の戻値としてエラーを返す方法にとって代わる方法のこと。
    エラーがプログラムの実行中に発生した場合に
    例外オブジェクトというもの (これ自体がクラスのインスタンス)を生成します。 
    これを例外の送出(スロー)といい
    例外オブジェクトを適切な方法で補足(キャッチ)して、 エラー処理をする。
    例外をキャッチしたい範囲があれば try ブロックで処理をかいて
    catch でリカバリをする処理をかく。
catch ブロックには、キャッチできる例外の型を指定する。
     try  // 例外の発生し得る範囲
     {
       throw "例外が発生しました";  // 例外をスローする
     }
     catch( const char* str )  // 例外をキャッチする
     {
       std::cout < <  str < <  std::endl;
     }
WARNING 
    この指定はできない。コンパイルエラーとなる。
    
    各関数はどの例外をなげるか宣言をする。
    例外の仕様という。
    throw() は例外を投げないことと宣言する。
    throw( runtime_error ) は runtime_error 型( またはその派生型 )の例外をなげると説明をする
    catch ( runtime_error ) {
      
    }
    // すべての例外型をキャッチする
    catch ( ... ) {
      
    }
    void func() throw( runtime_error );
■ 例外の使いどころ例外は無視できない。
    例外をなげる場合は、どこかでキャッチをしないとプログラムが終了する。
    つまりエラーがあればその場で即死させることができる。制御ロジックがエラーハンドルロジックと分離できる
    // エラーコードとして返す場合はチェックを無視できる。
    ErrorCode fileopen( string &path ) {
        if ( path ) {
          return E_INVALID_PATH;
        }
    }
    // 投げられた例外はどこかでとらえないとプログラムは終了する。
    void fileopen( string &path ) throw( InvalidFilePath );
    void fileopen( string &path ) {
        if ( path ) {
          throw InvalidFilePath( path );
        }
    }
    try {
      add( a )
      add( a )
      add( a )
      add( a )
    }
    catch ( ) {
      // ここでまとめてエラーハンドル
    }
    try {
      ret = add( a )
      if ( ret ) {
      }
      add( a )
      // エラーハンドル
      if ( ret ) {
      }
      add( a )
      if ( ret ) {
      }
      add( a )
    }
    catch ( ) {
    }
■ 例外を捕捉する全体で例外をキャッチするには main() 内でキャッチをする。もし main で捕捉できない例外があれば、main() の実行前に発生した例外かもしれない。
    静的なオブジェクトのコンストラク内で例外をとらえる。
    int main() {
      try {
      }
      catch (...) {
      }
      return 0;
    }
■ 例外処理をカスタマイズする■ terminate投げられた例外がキャッチされないと、 terminate() が呼ばれる。
    エラーのログをとり, リソースをすべて解放をして abort() をよぶ。
    文字とおり最後の処理をする。
    set_terminate() によって実装を変更できる。POINT
    main() 実行前に静的なオブジェクトの初期化が実行される。
    このときは 静的なオブジェクトのコンストラクタに set_terminate() をいれると捕捉をできる。
    void my_terminate() throw()
    {
      printf( "call my_terminate\n" );
      char buf[256];
      gets( buf );
      // エラーのログをとり、フラッシュする。
    }
    void testfunc() throw( runtime_error )
    {
      throw runtime_error( "test" );
    }
    int main() {
      set_terminate( my_terminate );
      testfunc();
    }
■ unexpected仕様にない例外をなげると, unexpected() をよばれる。
    デフォルトの処理は terminate() をよぶだけ。
    set_unexpected() によって内容を変更できる。
    unexpected() -> terminate() -> abort()
■ 例外クラスを捕捉する例外はシステムで定義すみのクラスがある。
    それ以外に任意の例外クラスを定義できる。
    呼び出し元は自分がエラーハンドルできる例外型を指定できる。POINT
    catch で捕獲できる例外オブジェクトは任意の型を補足できる。
    派生クラスもキャッチの対象になるので階層構造にしておくと便利。
    throw; とするとキャッチした例外を再度スローすることになる。
    つまり人に丸投げすることになる。
    try - catch をするのは次の条件をみたすとき。
    すべての関数よびだしで try - catch をする必要はない
  WARNING 
    リカバリーできない例外をキャッチするのは問題を先送りにしているだけ
    init() {
      try {
        File->open();
      }
      catch ( InvalidFileException ) {
        // InvalidFileException とその派生クラスの例外だけをとらえる。
        // それ以外の例外は無視されて、さらに上の関数へ伝播する
      }
    }
    void main() {
      try {
        init();
      }
      catch ( runtime_error ) {
        // init() 以下で捕捉されない例外はここに届く。
      }
    }
    
例外がなげられたときは スタック上のオブジェクトは デストラクタが実行される
    try {
    }
    catch () {
      // 何もしない
    }
■ 例外クラスを定義するPOINT
    例外は 基底クラスから必ず派生させる。
    こうすることで main でキャッチオールブロックを用意できることになるシステムが提供する 例外クラスもある
    int main() {
      try {
      }
      catch( exception e ) {
      }
    
    }
    class InvalidPath : public runtime_error {
      public:
        InvalidPath() throw();
    };
■ コンストラクタの例外コンストラクタも例外をなげることができる。
    コンストラクタで例外を投げるということは
    そのオブジェクトが未完全な状態でつくられる。メンバオブジェクトのコンストラクトに失敗した場合は、
    既にコンストラクト済みの他のオブジェクトのデストラクタがよばれる。
    T::T() throw( runtime_error )
    {
    }
■ アンワインドプロセス例外の実装は longjmp() と同じ。
    関数外の場所に制御をうつす。
    ただし 例外は スタックを戻してくれる。( unwind process  )
    スタック上のオブジェクトは デストラクタが実行される。
  POINT
    ただし /EHsc オプションをつけること
    指定しないとデストラクタが実行されない。■ GetCurrentProcessIdSYNTAX
    DWORD GetCurrentProcessId();
  DESC
    呼び出し側プロセスのプロセス識別子が返す。
  Kernel32.lib■ internal■ SymGetLineFromAddrSYNTAX
    BOOL SymGetLineFromAddr(
      HANDLE hProcess,
      DWORD dwAddr,
      PDWORD pdwDisplacement,
      PIMAGEHLP_LINE Line
    );    
  DESC
    指定されたアドレスに対応するソースコードの行を検索する
    imagehlp.lib■ GetFirstStackTrace■ symgetodulebase  SYNTAX
    DWORD SymGetModuleBase(
      HANDLE hProcess,  // 最初に SymInitialize() へ渡された、プロセスのハンドルを指定する。
      DWORD dwAddr      // SymLoadModule() を使ってロードしたモジュールのいずれかに含まれている有効な仮想アドレスを指定する。
    );
  DESC
    指定されたアドレスを保持するモジュールのベースアドレスを取得する。■ SymLoadModuleDWORD SymLoadModule(
  HANDLE hProcess, 
  HANDLE hFile,    
  PSTR ImageName, 
  PSTR ModuleName,
  DWORD BaseOfDll, 
  DWORD SizeOfDll  
);
  DESC
    シンボルテーブルをロードします。
 | 
 | 
  
NINJAIDX 12