2008-11-09 6 views
18

처리되지 않은 예외 (catch 블록 외부로 던져진 예외 포함)를 잡는 방법이 있습니까?처리되지 않은 모든 C++ 예외를 잡기?

나는 예외를 다룬 모든 정상적인 정리에 대해 정말로 신경 쓰지 않는다. 단지 잡을 수 있고, 로그에 기록하고 사용자에게 알리고 프로그램을 종료 할 수있다. 예외적으로이 사건은 일반적으로 치명적이기 때문에, 복구 할 수없는 오류. 같은

뭔가 :

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); 
} 

답변

21

이 예기치 않은 예외를 포착 할 수 있습니다. 시도의 catch 블록없이

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

, 난 당신이 예외를 잡을 수 있다고 생각합니다, 그래서 당신의 프로그램을 구성, 그래서 코드를 thowing를 제외하고는 시도/캐치의 통제하에하지 않습니다.

+0

것은 정말 내가 아는 일부를 프로그래머 ... 성능이 좀 중요하기 때문에 ... 하나의 큰 '슈퍼 시도 "블록에 내 전체 응용 프로그램을 넣어 싶지 않는 것입니다 어딘가에 어딘가에 있기 때문에 Visual Studio 예를 들어 감지 할 수/catch/어떤 exceptionsn 및 휴식과 디버깅을 제공합니다. –

+0

수퍼 try 블록이 작동합니다. 당신은 메인에 한 번 설치 비용을 지불합니다. 한 번은 성능 문제가 아닙니다. – EvilTeach

+0

한 번만? 한 번 try 블록 안에 던진 후에 정리를위한 일종의 "trace"를 유지했는데 블록의 내용을 기반으로 비용을 산출 했습니까? –

4

이것은 내가 항상) (주에서 할

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! 
    } 
} 
+1

그건 좋은 방법입니다,하지만 이것은 정적 초기화 예외를 잡을 수는 없다는 것을 명심해야합니다 (저는 믿습니다). – kralyk

+0

@kralyk : 정적 저장 기간 개체의 생성자/소멸자에서 생성 된 예외를 catch 할 수있는 방법은 없습니다. 이 경우'std :: terminate()'가 호출됩니다. –

+1

알아요 ... 기술적으로 set_terminate() (내 대답 참조)를 사용하여 가능할 수도 있지만 정적 초기화 순서는 구현에 따라 정의되었으므로 보장 할 수 없습니다. – kralyk

9

당신은 모든 처리되지 않은 SEH 예외를 잡을 것이다, Windows에서 SetUnhandledExceptionFilter을 사용할 수있는 것입니다.

일반적으로 모든 문제에 대해 IIRC로 충분하므로 모든 C++ 예외가 SEH로 구현됩니다.

8

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"; 
    } 
} 
+2

Windows의 .dmp 파일은 대략 핵심 파일과 동일하지만 사용자의 하드 드라이브를 흩 뜨리는 대신 사용자가 "보내기"를 클릭하면 Windows 오류보고 웹 사이트에 업로드됩니다. 또한 just-in-time 디버거가 구성된 경우 Windows 대신 디버거가 중단됩니다. – bk1e

+1

std :: string의 생성자 자체가 예외를 던질 수 있습니다. 그리고 std : cerr에 인쇄하는 것도 마찬가지입니다. 그런 다음 다시 99 %의 운이 좋을 것입니다. – rxantos

7

업데이트 : 이것은 ++ 98 만 c를 포함한다.

Meyers (pg 76)가 More Effective C++에서 함수가 예외 스펙에 정의되지 않은 예외를 생성 할 때 호출되는 함수를 정의 할 수 있습니다. 응용 프로그램에서

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()가 호출되는 것이다

예외 사양을 사용하는 경우 작동합니다. ; (

+3

이 대답은 C++ 11 표준이 나오기 훨씬 전에 만들어졌지만 현재'std :: set_unexpected'는 더 이상 사용되지 않습니다. – scrutari

1

모든 예외 장벽 (기본 스레드뿐만 아니라)에서 catch (...)를 사용하십시오. 항상 (...) 다시 게시하여 표준 출력/오류를 로그 파일로 리디렉션하는 것이 좋습니다. 당신은 의미있는 RTTI를 할 수 없습니다 (...).OTOH, GCC 같은 컴파일러를 출력 처리되지 않은 예외에 대한 매우 상세한 설명 : std::set_terminate()

19

체크 아웃 다만,이 방법 월 사용 (: http://en.cppreference.com/w/cpp/error/rethrow_exception에서 예 참조)이

unexpected exception: wrong input parameters 
Aborted 
같은 것을 가지고 :

#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; 
} 

이러한 접근 방식은 또한 당신이 처리되지 않은 예외 콘솔 출력을 사용자 정의 할 수 있습니다 대신이의

:

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

'terminate_handler'에서 예외에 접근 할 수 있습니까? –

+0

@ KonstantinA.Magg 나는 그렇게 생각하지 않는다. 예외가 _any_ 유형이 될 수 있기 때문에 실제로 액세스 할 수있는 방법이 없습니다 ... – kralyk

+1

예 std :: uncaugth_exception() 및 std :: current_exception {)을 사용할 수 있습니다 –

3

C++ (11)가 사용할 수있는 타입의 값 등 무엇()

관련 문제