[英]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.