web-dev-qa-db-ja.com

未処理のC ++例外をすべてキャッチしますか?

処理されない例外(catchブロックの外でスローされたものを含む)をキャッチする方法はありますか?

これらの場合の例外は一般的に致命的で回復不可能なエラーであるため、例外を使用して行われるすべての通常のクリーンアップ処理については本当に気にしていません。それをキャッチして、ユーザーにログを記録/通知し、プログラムを終了することができます。

何かのようなもの:

global_catch()
{
    MessageBox(NULL,L"Fatal Error", L"A fatal error has occured. Sorry for any inconvience", MB_ICONERROR);
    exit(-1);
}
global_catch(Exception *except)
{
    MessageBox(NULL,L"Fatal Error", except->ToString(), MB_ICONERROR);
    exit(-1);
}
23
Fire Lancer

これは、予期しない例外をキャッチするために使用できます。

catch (...)
{
    std::cout << "OMG! an unexpected exception has been caught" << std::endl;
}

トライキャッチブロックがないと、例外をキャッチできないと思うので、プログラムを構成して、例外をスローするコードがトライ/キャッチの制御下にあるようにします。

25
EvilTeach

チェックアウト std::set_terminate()

19
kralyk

Windowsでは SetUnhandledExceptionFilter を使用できます。これにより、未処理のすべてのSEH例外がキャッチされます。

IIRCのすべてのC++例外はSEHとして実装されているため、通常はこれですべての問題に十分です。

10
gbjbaanb

Catchブロックがないと、例外をキャッチできません。 main()にcatch(...)ブロックを含めることができます(追加のスレッドごとに同等のもの)。このcatchブロックでは、例外の詳細を回復し、ロギングや終了など、それらについて何かを行うことができます。

ただし、一般的なcatch(...)ブロックにはマイナス面もあります。システムは、例外がユーザーによって処理されたことを検出するため、それ以上のヘルプは提供されません。 Unix/Linuxでは、このヘルプはCOREファイルの作成を構成します。これをデバッガにロードして、例外ではない例外の元の場所を確認できます。 catch(...)で処理している場合、この情報はすでに失われています。

WindowsにはCOREファイルがないため、catch(...)ブロックを使用することをお勧めします。そのブロックから、通常は実際の例外を復活させる関数を呼び出します。

std::string ResurrectException()
   try {
       throw;
   } catch (const std::exception& e) {
       return e.what();
   } catch (your_custom_exception_type& e) {
       return e.ToString();
   } catch(...) {
       return "Ünknown exception!";
   }
}


int main() {
   try {
       // your code here
   } catch(...) {
       std::string message = ResurrectException();
       std::cerr << "Fatal exception: " << message << "\n";
   }
}
8
paavo256

Update:これはc ++ 98のみを対象としています。

Meyersによる より効果的なC++ から(76ページ)、関数がその例外仕様で定義されていない例外を生成したときに呼び出される関数を定義できます。

void convertUnexpected()
{
    // You could redefine the exception here into a known exception
    // throw UnexpectedException();

    // ... or I suppose you could log an error and exit.
}

アプリケーションに関数を登録します。

std::set_unexpected( convertUnexpected );

関数convertUnexpected()は、関数がその例外仕様で定義されていない例外を生成した場合に呼び出されます...これは、例外仕様を使用している場合にのみ機能します。 ;(

7
paxos1977

これは私がいつもmain()で行うことです

int main()
{
    try
    {
        // Do Work
    }
    catch(std::exception const& e)
    {
         Log(e.what());
         // If you are feeling mad (not in main) you could rethrow! 
    }
    catch(...)
    {
         Log("UNKNOWN EXCEPTION");
         // If you are feeling mad (not in main) you could rethrow! 
    }
}
4
Martin York

C++ 11が利用可能であれば、このアプローチを使用できます(例: http://en.cppreference.com/w/cpp/error/rethrow_exception ):

#include <iostream>
#include <exception>

void onterminate() {
  try {
    auto unknown = std::current_exception();
    if (unknown) {
      std::rethrow_exception(unknown);
    } else {
      std::cerr << "normal termination" << std::endl;
    }
  } catch (const std::exception& e) { // for proper `std::` exceptions
    std::cerr << "unexpected exception: " << e.what() << std::endl;
  } catch (...) { // last resort for things like `throw 1;`
    std::cerr << "unknown exception" << std::endl;
  }
}

int main () {
  std::set_terminate(onterminate); // set custom terminate handler
  // code which may throw...
  return 0;
}

このアプローチでは、未処理の例外のコンソール出力をカスタマイズすることもできます。

unexpected exception: wrong input parameters
Aborted

これの代わりに:

terminate called after throwing an instance of 'std::logic_error'
  what():  wrong input parameters
Aborted
4
scrutari

メインスレッドだけでなく、すべての例外バリアでキャッチ(...)を使用します。 (...)で意味のあるRTTIを実行できないため、常に再スロー(...)して標準出力/エラーをログファイルにリダイレクトすることをお勧めします。 OTOH、GCCのようなコンパイラーは、ハンドルされていない例外に関するかなり詳細な説明を出力します:タイプ、what()の値など。

1
ididak