27

そうでなければ処理されない例外 (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);
}
4

8 に答える 8

27

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

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

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

于 2008-11-09T16:54:24.293 に答える
26

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

編集:これは、例外一致を使用した本格的な例です。

#include <iostream>
#include <exception>
#include <stdexcept>

struct FooException: std::runtime_error {
    FooException(const std::string& what): std::runtime_error(what) {}
};

int main() {
    std::set_terminate([]() {
        try {
            std::rethrow_exception(std::current_exception());
        } catch (const FooException& e) {
            std::cerr << "Unhandled FooException: " << e.what() << std::endl;
        } catch (const std::exception& e) {
            std::cerr << "Unhandled exception: " << e.what() << std::endl;
        } catch (...) {
            std::cerr << "Unhandled exception of unknown type" << std::endl;
        }

        std::abort();
    });

    throw FooException("Bad things have happened.");
    // throw std::runtime_error("Bad things have happened.");
    // throw 9001;
}
于 2012-03-08T13:51:59.403 に答える
12

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

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

于 2008-11-09T17:24:24.327 に答える
9

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";
   }
}
于 2008-11-09T18:34:49.333 に答える
7

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

Meyers による「より効果的な C++」(pg 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() は、関数が例外仕様で定義されていない例外を生成した場合に呼び出されます...つまり、例外仕様を使用している場合にのみ機能します。;(

于 2008-11-09T18:44:54.290 に答える
6

これは、私が常に 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! 
    }
}
于 2008-11-09T17:11:14.337 に答える
5

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
于 2016-06-21T14:33:59.687 に答える
1

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

于 2008-11-09T22:35:13.060 に答える