簡體   English   中英

捕獲所有未處理的C ++異常?

[英]Catching all unhandled C++ exceptions?

有沒有辦法捕獲原本未處理的異常(包括那些在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);
}

這可用於捕獲意外的異常。

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

如果沒有try catch塊,我認為你不能捕獲異常,所以構造你的程序,以便異常的代碼在try / catch的控制之下。

您可以在Windows上使用SetUnhandledExceptionFilter ,它將捕獲所有未處理的SEH異常。

通常,這對於您的所有問題都已足夠,因為IIRC將所有C ++異常實現為SEH。

沒有任何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";
   }
}

更新 :這僅涵蓋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()...這意味着只有在使用異常規范時這才有效。

這是我總是在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! 
    }
}

如果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

在所有異常障礙(不僅僅是主線程)中使用catch(...)。 我建議你總是重新拋出(...)並將標准輸出/錯誤重定向到日志文件,因為你不能在(...)上做有意義的RTTI。 OTOH,像GCC這樣的編譯器將輸出關於未處理異常的相當詳細的描述:類型,what()的值等。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM