トップページ
ひらく | たたむ | ページトップ
↓マウスで反転選択した文字を検索
C++
   
ページ内検索 ページ外検索
検索したい文字を入力して
ENTERを押すと移動します。
\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 でリカバリをする処理をかく。


     try  // 例外の発生し得る範囲
     {
       throw "例外が発生しました";  // 例外をスローする
     }
     catch( const char* str )  // 例外をキャッチする
     {
       std::cout < <  str < <  std::endl;
     }
catch ブロックには、キャッチできる例外の型を指定する。
    catch ( runtime_error ) {
      
    }

    // すべての例外型をキャッチする
    catch ( ... ) {
      
    }
WARNING この指定はできない。コンパイルエラーとなる。
    catch () {
    
    }
各関数はどの例外をなげるか宣言をする。 例外の仕様という。 throw() は例外を投げないことと宣言する。
    void func() throw();
throw( runtime_error ) は runtime_error 型( またはその派生型 )の例外をなげると説明をする
    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() 内でキャッチをする。
    int main() {
      try {

      }
      catch (...) {

      }
      return 0;
    }
もし main で捕捉できない例外があれば、main() の実行前に発生した例外かもしれない。 静的なオブジェクトのコンストラク内で例外をとらえる。
    MemoryManager gManager;

    


___

■ 例外処理をカスタマイズする

___

■ terminate

投げられた例外がキャッチされないと、 terminate() が呼ばれる。 エラーのログをとり, リソースをすべて解放をして abort() をよぶ。 文字とおり最後の処理をする。 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();
    }

POINT main() 実行前に静的なオブジェクトの初期化が実行される。 このときは 静的なオブジェクトのコンストラクタに set_terminate() をいれると捕捉をできる。
___

■ unexpected

仕様にない例外をなげると, unexpected() をよばれる。 デフォルトの処理は terminate() をよぶだけ。 set_unexpected() によって内容を変更できる。
    unexpected() -> terminate() -> abort()
___

■ 例外クラスを捕捉する

例外はシステムで定義すみのクラスがある。 それ以外に任意の例外クラスを定義できる。 呼び出し元は自分がエラーハンドルできる例外型を指定できる。

    init() {
      try {
        File->open();
      }
      catch ( InvalidFileException ) {
        // InvalidFileException とその派生クラスの例外だけをとらえる。
        // それ以外の例外は無視されて、さらに上の関数へ伝播する
      }
    }



    void main() {

      try {
        init();
      }
      catch ( runtime_error ) {
        // init() 以下で捕捉されない例外はここに届く。
      }

    }
    

POINT catch で捕獲できる例外オブジェクトは任意の型を補足できる。 派生クラスもキャッチの対象になるので階層構造にしておくと便利。 throw; とするとキャッチした例外を再度スローすることになる。 つまり人に丸投げすることになる。
    catch {
      throw;
    }
try - catch をするのは次の条件をみたすとき。 すべての関数よびだしで try - catch をする必要はない
     例外をなげる可能性があるとき
     その例外をリカバリーできるとき
WARNING リカバリーできない例外をキャッチするのは問題を先送りにしているだけ
    try {

    }
    catch () {
      // 何もしない
    }
例外がなげられたときは スタック上のオブジェクトは デストラクタが実行される
___

■ 例外クラスを定義する

POINT 例外は 基底クラスから必ず派生させる。 こうすることで main でキャッチオールブロックを用意できることになる
    int main() {
      try {

      }
      catch( exception e ) {

      }
    
    }
システムが提供する 例外クラスもある
    #include< stdexcept> 
    #include< exception> 

     runtime_error
     overflow_error
     underflow_error
    class InvalidPath : public runtime_error {
      public:
        InvalidPath() throw();
    };

___

■ コンストラクタの例外

コンストラクタも例外をなげることができる。 コンストラクタで例外を投げるということは そのオブジェクトが未完全な状態でつくられる。
    T::T() throw( runtime_error )
    {

    }

メンバオブジェクトのコンストラクトに失敗した場合は、 既にコンストラクト済みの他のオブジェクトのデストラクタがよばれる。
___

■ アンワインドプロセス

例外の実装は longjmp() と同じ。 関数外の場所に制御をうつす。 ただし 例外は スタックを戻してくれる。( unwind process ) スタック上のオブジェクトは デストラクタが実行される。 POINT ただし /EHsc オプションをつけること 指定しないとデストラクタが実行されない。


___

■ GetCurrentProcessId

SYNTAX DWORD GetCurrentProcessId(); DESC 呼び出し側プロセスのプロセス識別子が返す。 Kernel32.lib
___

■ internal

___

■ SymGetLineFromAddr

SYNTAX 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 指定されたアドレスを保持するモジュールのベースアドレスを取得する。
___

■ SymLoadModule

DWORD SymLoadModule( HANDLE hProcess, HANDLE hFile, PSTR ImageName, PSTR ModuleName, DWORD BaseOfDll, DWORD SizeOfDll ); DESC シンボルテーブルをロードします。

NINJAIDX 12