모든 예외를 잡는 C ++


244

Java와 동등한 C ++이 있습니까?

try {
    ...
}
catch (Throwable t) {
    ...
}

기본 Windows 기능을 호출하는 Java / jni 코드를 디버깅하려고하는데 가상 시스템이 계속 충돌합니다. 네이티브 코드는 단위 테스트에서 잘 보이고 jni를 통해 호출 할 때만 충돌하는 것 같습니다. 일반적인 예외 포착 메커니즘은 매우 유용합니다.



2
대부분의 충돌은 C ++의 예외로 인해 발생하지 않습니다. 모든 예외를 잡을 수는 있지만 많은 충돌을 막을 수는 없습니다.
Mooing Duck

답변:


335
try{
    // ...
} catch (...) {
    // ...
}

모든 C ++ 예외를 포착하지만 나쁜 디자인으로 간주해야합니다. c ++ 11의 새로운 current_exception 메커니즘을 사용할 수 있지만 c ++ 11 (재 작성이 필요한 레거시 코드 시스템)을 사용할 수 없으면 메시지 나 이름을 얻는 데 사용할 명명 된 예외 포인터가 없습니다. . 포착 할 수있는 다양한 예외에 대해 별도의 catch 절을 추가하고 맨 아래에있는 모든 항목 만 포착하여 예기치 않은 예외를 기록 할 수 있습니다. 예 :

try{
    // ...
} catch (const std::exception& ex) {
    // ...
} catch (const std::string& ex) {
    // ...
} catch (...) {
    // ...
}

68
const 참조로 예외를 잡는 것이 좋습니다. 에서와 같이 : catch (std :: exception const & ex) {/ * ... * /}
coryan

12
@ coryan : const 참조로 잡는 것이 왜 좋은 습관입니까?
Tim MB

19
불필요한 사본을 피하는 것이 하나의 이점입니다.
Greg D

21
-1 : 이것이 "C ++의 모든 예외를 포착 할 것"이라는 제안은 오해의 소지가 있습니다. try 블록 내에서 0으로 나누기 오류를 생성하십시오. 발견되지 않은 예외가 발생하지만 코드는 C ++로 명확하게 나타납니다. 이것이 "모든 C ++ 예외를 잡을 것"이라고 말한 다음 제한된 유용성에 대한 메모에 구조적 예외에 대한 언급을 추가하는 것이 더 도움이 될 것입니다.
omatai

42
@omatai : 모든 C ++ 예외를 포착합니다. 0으로 나누기는 정의되지 않은 동작이며 C ++ 예외를 생성하지 않습니다.
Mooing Duck

151

누군가는 C ++ 코드에서 "크래쉬"를 잡을 수 없다고 덧붙여 야한다. 그들은 예외를 던지지 않지만 좋아하는 것을합니다. 널 포인터 역 참조로 인해 프로그램이 중단되면 정의되지 않은 동작을 수행하는 것입니다. 없습니다std::null_pointer_exception . 예외를 잡으려고해도 도움이되지 않습니다.

누군가 가이 스레드를 읽고 프로그램 충돌의 원인을 얻을 수 있다고 생각하는 경우를 대비하여. 대신 gdb와 같은 디버거를 사용해야합니다.


4
Shy가 지적했듯이 VC 컴파일러로 가능합니다. 좋은 생각은 아니지만 가능합니다.
Shog9

7
그래 SEH와 함께. 그러나 제정신 표준 C ++ 기술로는 그렇지 않습니다 :) 잘 창에 붙어 있으면 거의 모든 것을 할 수 있습니다 :)
Johannes Schaub-litb

1
음 ...이 고마워요. null 포인터 예외가 발생하지 않는 이유에 대한 답변을 찾고 있습니다!
Dalin Seivewright

10
Windows에서 SEH를 사용하고 POSIX 시스템에서 signal (2) / sigaction (2)을 사용하여 segfault를 잡을 수 있습니다. POSIX 시스템은 오늘날 사용중인 대다수의 시스템을 포괄하지만 예외 처리와 마찬가지로 일반적인 흐름 제어에 사용해야하는 것은 아닙니다. "죽기 전에 유용한 일을하는 것"에 가깝습니다.
Adam Rosenfield

1
@AdamRosenfield는 try { .. } catch(...) { ... }신호 / 서명을 사용하여 잡기 위해 구현할 때까지 "캐치"라고 부르지 않을 것입니다. : 신호 처리기에서 프로그래머가 코드에서 충돌이 발생한 위치를 알기가 비교적 어렵습니다. try / catch와 비교하여 프로그래밍 방식으로 감지하는 방법).
Johannes Schaub-litb

72

catch(...)GCC를 사용하여 필요한 경우 예외 유형을 내부에서 리버스 엔지니어링 할 수있는 방법입니다 (타사 라이브러리에서 알 수없는 경우 유용 할 수 있음).

#include <iostream>

#include <exception>
#include <typeinfo>
#include <stdexcept>

int main()
{
    try {
        throw ...; // throw something
    }
    catch(...)
    {
        std::exception_ptr p = std::current_exception();
        std::clog <<(p ? p.__cxa_exception_type()->name() : "null") << std::endl;
    }
    return 1;
}

부스트 를 사용할 여유가 있다면 캐치 섹션을 더 간단하게 (외부에서) 크로스 플랫폼으로 만들 수 있습니다

catch (...)
{
    std::clog << boost::current_exception_diagnostic_information() << std::endl;
}

58
try {
   // ...
} catch (...) {
   // ...
}

참고 그 ...안에catch 즉, 실제 줄임표이다. 세 개의 점.

그러나 C ++ 예외는 반드시 기본 Exception클래스의 서브 클래스 일 필요 는 없으므로이 구문을 사용할 때 발생하는 예외 변수를 실제로 볼 수있는 방법은 없습니다.


24
C ++ 11에는 다음이 있습니다 : try {std :: string (). at (1); // std :: out_of_range를 생성합니다.} catch (...) {eptr = std :: current_exception (); // 캡처}
Mohammad Alaggan

2
@ bfontaine : 그렇습니다. 그러나 C ++ 구문이 아닌 catch주석 ( // ...) 에서 기존 코드 자리 표시 자와 지정자 를 구별한다고 말했습니다 .
Greg Hewgill

1
@GregHewgill : 그렇습니다. 그것은 단지 인쇄상의 nitpicking이었습니다.
bfontaine

1
@ bfontaine : 충분합니다. :)
Greg Hewgill

44

모든 예외를 이식 가능한 방식으로 잡을 수는 없습니다 (C ++에서). 일부 예외는 C ++ 컨텍스트에서 예외가 아니기 때문입니다. 여기에는 0으로 나누기 오류 및 기타 항목이 포함됩니다. 이러한 오류가 발생할 때 해킹하여 예외를 던질 수는 있지만, 쉽게 수행 할 수없고 이식 가능한 방식으로 올바르게 얻는 것은 쉽지 않습니다.

모든 STL 예외를 잡으려면 할 수 있습니다

try { ... } catch( const std::exception &e) { ... }

을 사용하면 e.what()을 반환 const char*하여 예외 자체에 대해 더 많이 알 수 있습니다. 이것은 당신이 가장 많이 요구 한 Java 구조와 유사한 구조입니다.

누군가가 상속받지 않은 예외를 던질만큼 바보 인 경우에는 도움이되지 않습니다 std::exception.


2
왜 이것이 상단에 있지 않습니까?
Ivan Sanz-Carasa

31

요컨대을 사용하십시오 catch(...). 그러나 기본적으로 다음 catch(...)과 함께 사용됩니다 throw;.

try{
    foo = new Foo;
    bar = new Bar;
}
catch(...)       // will catch all possible errors thrown. 
{ 
    delete foo;
    delete bar;
    throw;       // throw the same error again to be handled somewhere else
}

이것이 올바른 사용 방법 catch(...)입니다.


6
이 예외 상황을 자동으로 처리하는 메모리 관리에 RAII를 사용하는 것이 좋습니다.
paykoob

1
@paykoob 새 foo를 만들려고했지만 바에서 실패한 경우를 어떻게 처리합니까? 또는 bar의 생성자가 파일을 열려고하지만 실패하여 던질 때. 다음은 dangeling foo에 끝낼 수도
Mellester

2
@MelleSterk이 경우에도 여전히 스택이 정리되지 Foo않습니까? 소멸자 가 실행 됩니까? 나는 그것이 RAII의 요점이라고 생각했다. 그러나 스택에 스택을 Foo생성 하는 대신 포인터가 필요한 경우 Foo스택에 선언 된 다른 포인터로 래핑해야합니다.
reirab

예 auto foo = std :: make_unique <Foo> (); 자동 바 = std :: make_unique <Bar> (); // 예외 안전하고 누출되지 않으며 catch (...)가 필요하지 않습니다.
paulm

이 답변은 토론이 시작된 경우에만 투표 할 가치가 있습니다. :)
Cristik

21

다음과 같이 작성하면됩니다 :

try
{
  //.......
}
catch(...) // <<- catch all
{
  //.......
}

그러나 여기에는 눈에 띄지 않는 위험이 있습니다. try블록 에 발생한 정확한 유형의 오류를 찾을 수 없으므로 catch예외 유형에 관계없이 프로그램이 지속되어야한다는 것을 확신 할 때이 유형을 사용 하십시오 catch블록에 정의 된 방식으로 .


31
우수 답변이 제공된 후 거의 5 년 동안 질문에 답변 할 수있는 배지를 받으 셨기를 바랍니다.


18

당신이 사용할 수있는

catch(...)

그러나 그것은 매우 위험합니다. John Robbins는 자신의 저서 인 Debugging Windows 에서 catch (...) 명령에 의해 가려진 정말 불쾌한 버그에 대한 전쟁 이야기를 들려줍니다. 특정 예외를 잡는 것이 훨씬 낫습니다. try 블록이 합리적으로 발생할 수 있다고 생각하는 것을 잡으십시오.하지만 실제로 예기치 않은 일이 발생하면 코드에서 예외를 더 높게 발생시킵니다.


1
방금 이것들의 사용법을 포착하고 그 단계에서 약간의 벌채를 피했습니다. 예외없이 아무것도하지 않는 것은 분명히 문제를 요구합니다.
jxramos

15

여기에 이것을 언급하겠습니다 : Java

try 
{
...
}
catch (Exception e)
{
...
}

모든 예외를 잡을 수는 없습니다! 나는 실제로 이런 종류의 일이 전에 일어 났으며, 그것은 도발적인 일입니다. 예외는 Throwable에서 파생됩니다. 문자 그대로 모든 것을 잡기 위해 예외를 잡기를 원하지 않습니다. Throwable을 잡고 싶습니다.

나는 그것이 nitpicky처럼 들리지만, 당신이 try ... catch (Exception e) "블록으로 둘러싸인 코드에서"언제나 예외 "가 어디서 왔는지 알아 내려고 며칠을 보냈을 때 당신.


2
물론, 당신은 절대로 Error 객체를 잡아서는 안됩니다. 만약 잡아야한다면 예외가 될 것입니다. 오류 개체는 힙 공간 부족과 같은 완전히 치명적인 것입니다.
SCdF

1
GoodProgrammerExpected 예외가 대부분인 런타임 예외도 없습니다 !!!
OscarRyz

3
우리는 catch (Throwable) 블록으로 인해 OutOfMemoryError를 잡아서 사물을 죽이지 않고 실제로 심각한 버그가 발생했습니다 ...
Trejkaz

1
물론 catch(Exception)Java에서 모든 예외를 잡을 수는 없습니다. C # ... Java = catch(Thowable), C # = 과 섞여 catch(Exception)있습니다. 혼동하지 마십시오.
요리사 파라오

2
@OscarRyz 저것 CoderMalfunctionError은 (실제로 자바 Error서브 클래스입니다 ... 소리가 나지 않는 것은 아닙니다.)
reirab

9

예를 들어 미니 덤프를 만들기 위해 모든 예외를 잡으려면 ...

누군가가 Windows에서 작업을 수행했습니다.

http://www.codeproject.com/Articles/207464/Exception-Handling-in-Visual-Cplusplus를 참조 하십시오 .이 기사에서는 모든 종류의 예외를 포착하는 방법을 발견하고 작동하는 코드를 제공합니다.

잡을 수있는 목록은 다음과 같습니다.

 SEH exception
 terminate
 unexpected
 pure virtual method call
 invalid parameter
 new operator fault 
 SIGABR
 SIGFPE
 SIGILL
 SIGINT
 SIGSEGV
 SIGTERM
 Raised exception
C++ typed exception

그리고 사용법 : CCrashHandler ch; ch.SetProcessExceptionHandlers (); // 하나의 스레드에 대해이 작업을 수행합니다. ch.SetThreadExceptionHandlers (); // 각 쓰레드마다


기본적으로 현재 디렉토리 (crashdump.dmp)에 미니 덤프가 생성됩니다.


4

일반적인 예외 포착 메커니즘은 매우 유용합니다.

못 미더운. 코드가 충돌했기 때문에 이미 코드가 손상되었음을 알고 있습니다. 예외를 먹는 것은 이것을 숨길 수도 있지만 아마도 더 나쁘고 더 미묘한 버그가 발생할 수도 있습니다.

당신이 정말로 원하는 것은 디버거입니다 ...


13
동의하지 않습니다. 실시간 응용 프로그램에는 알 수없는 예외를 포착 하고 로그에 무언가 를 쓰거나 응용 프로그램이 충돌하지 않도록 일반적인 오류 과정을 추구하는 경우가 많이 있습니다.
f0ster

3
차라리 당신이 경우있는 거 생각 의심 할 수 편리 스택이 휴지통 또는 메모리가 소모 및 일반 오류 처리 중 하나 성공하지 않을 것입니다 어디에 사람들을 무시하는 행동의 몇 가지 일반적인 오류 과정을 추구합니다. 당신이 그 오류를 잡기와 아무것도 잘못된 를 복구하지만, 이럴 포괄 정말 전용으로 (별도의 스택, 사전 할당 된 메모리를) 격리 존재한다 프로그램 종료 직전이라고 조심스럽게 작성 로직; 문제가 무엇인지 모른다면 복구 할 수 있다고 확신 할 수 없습니다.
Shog9

1
즉, 프로그램이 충돌 한 곳과 그 이유를 알아 내기 위해 런타임 동안 빌드 한 일부 로그를 풀어주는 신호 처리기를 설치하십시오.
Cleared

3
  1. 콘솔 창에서 JNI를 사용하는 Java 애플리케이션을 실행하여 (Java 명령 행에서 실행) JVM이 충돌하기 전에 발견 된 내용에 대한 보고서가 있는지 확인할 수 있습니다. Java 창 응용 프로그램으로 직접 실행하는 경우 대신 콘솔 창에서 실행하면 표시되는 메시지가 누락 될 수 있습니다.

  2. 둘째, JNI DLL 구현을 스텁하여 DLL의 메소드가 JNI에서 입력되고 올바르게 리턴되는지 등을 보여줄 수 있습니까?

  3. C ++ 코드에서 JNI- 인터페이스 메소드 중 하나를 잘못 사용하여 문제점이 발생하는 경우 간단한 JNI 예제가 컴파일되어 설정과 작동하는지 확인 했습니까? 특히 매개 변수를 네이티브 C ++ 형식으로 변환하고 함수 결과를 Java 유형으로 변환하기 위해 JNI 인터페이스 메소드를 사용하려고 생각합니다. 데이터 변환이 작동하고 COM과 유사한 호출에서 JNI 인터페이스로 이동하지 않도록하기 위해 이들을 스텁하는 것이 유용합니다.

  4. 확인해야 할 다른 것들이 있지만, 네이티브 Java 메소드가 무엇인지, 그리고 JNI 구현이 무엇을 시도하는지에 대해 더 알지 못하면 제안하기가 어렵습니다. C ++ 코드 수준에서 예외를 잡는 것이 문제와 관련이 있는지 확실하지 않습니다. (JNI 인터페이스를 사용하여 예외를 Java로 다시 던질 수는 있지만, 이것이 제공하는 것이 확실하지는 않습니다.)


2

JNI를 사용하는 프로그램을 제대로 디버깅 할 수 없다는 실제 문제 (또는 디버거에서 실행할 때 버그가 나타나지 않음) :

이 경우 JNI 호출 주위에 Java 래퍼를 추가하는 것이 도움이됩니다 (즉, 모든 기본 메소드는 개인용이며 클래스의 공용 메소드는이를 호출하여). 해제 후) 또는 동기화 (하나의 DLL에서 단일 객체 인스턴스로 모든 메소드를 동기화) 후에는 사용되지 않습니다. 자바 래퍼 메소드가 실수를 기록하고 예외를 던지도록하십시오.

이것은 종종 대규모 병렬 Java 프로그램을 디버그하려고 시도하는 것보다 실제 오류 (놀랍게도 대부분 불쾌한 더블 프리 또는 이와 유사한 원인이되는 호출 된 함수의 의미를 따르지 않는 Java 코드에 있음)를 찾는 데 도움이됩니다. 네이티브 디버거 ...

원인을 알고 있으면 코드를 피하는 래퍼 메소드에 코드를 보관하십시오. JNI 코드가 VM을 충돌시키는 것보다 래퍼 메소드가 예외를 발생시키는 것이 좋습니다 ...


1

글쎄, 이것은 실제로 컴파일러 환경에 달려 있습니다. gcc는 이것을 잡지 않습니다. Visual Studio와 내가 사용한 마지막 Borland가 그랬습니다.

따라서 충돌에 대한 결론은 개발 환경의 품질에 달려 있다는 것입니다.

C ++ 사양에 따르면 catch (...)는 예외를 잡아야하지만 모든 경우에 해당되는 것은 아닙니다.

적어도 내가 시도한 것에서.


1

알고

try{
// ...
} catch (...) {
// ...
}

캐치 유일한 언어 수준의 예외 같은 다른 낮은 수준의 예외 / 오류 Access Violation및이 Segmentation Fault잡힐 실 거예요.


Segmentation Fault와 같은 것은 실제로 예외가 아니라 신호입니다. 따라서 일반적인 예외처럼 잡을 수 없습니다. 그러나 이와 같은 해결 방법 있습니다.
MAChitgarha
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.