C ++ 프로그램이 모든 예외를 잡아 내고 예외가 main ()을지나 가지 못하게해야합니까?


29

나는 C ++ 프로그램이 궁극적으로 모든 예외를 잡아야한다는 조언을 받았다. 당시의 추론은 본질적으로 예외가 main()이상한 좀비 상태 로 들어가 도록 허용하는 프로그램이었습니다 . 나는 몇 년 전에 이것을 들었고, 되돌아 보면 관찰 된 현상은 문제의 프로젝트에서 매우 큰 코어 덤프의 긴 생성으로 인한 것이라고 생각합니다.

당시 이것은 기괴하지만 설득력이있는 것처럼 보였다. C ++이 모든 예외를 잡아 내지 않은 것에 대해 프로그래머를 "처벌"해야한다는 것은 전적으로 무의미한 일이지만, 내 앞의 증거는 이것을 뒷받침하는 것처럼 보였다. 문제의 프로젝트에서 포착되지 않은 예외를 던진 프로그램은 이상한 좀비 상태로 들어가는 것처럼 보였습니다. 또는 원인이 지금 의심되는 것처럼 원치 않는 코어 덤프 중 프로세스는 비정상적으로 중지하기가 어렵습니다.

(이 시점에서 왜 이것이 더 명확하지 않은지 궁금한 사람은 프로젝트가 여러 프로세스에서 여러 파일로 많은 양의 출력을 생성하여 모든 종류의 aborted (core dumped)메시지 를 효과적으로 모호하게 했으며이 경우 코어 덤프에 대한 사후 검사는 없었습니다. "중요한 디버깅 기술이 아니기 때문에 코어 덤프에 대해서는 많은 생각이 없었습니다. 프로그램 문제는 일반적으로 오래 지속되는 프로그램에 의해 시간이 지남에 따라 많은 이벤트에서 누적 된 상태에 의존하지 않고 짧은 실행 프로그램에 대한 초기 입력 (< 1 시간) 그래서 더 많은 정보를 얻기 위해 디버그 빌드 또는 디버거에서 동일한 입력으로 프로그램을 다시 실행하는 것이 더 실용적이었습니다.)

현재 예외를 남기지 않기위한 목적으로 만 예외를 포착하는 데 큰 이점이 있는지 여부는 확실하지 않습니다 main().

예외가 과거 main()에 발생했을 때 생각할 수있는 작은 이점 은 결과가 std::exception::what()터미널에 인쇄된다는 것입니다 (최소한 Linux에서는 gcc 컴파일 프로그램 사용). 반면에,이 대신에서 파생 된 모든 예외를 잡기에 의해 달성하기 위해 사소한 std::exception및 결과 인쇄 std::exception::what()하고에서 파생되지 않는 예외의 메시지 인쇄하는 것이 바람직의 경우 std::exception가 그 다음 해야한다 떠나기 전에 잡힐 main()인쇄에 위해를 메시지.

예외가 과거에 발생하도록 허용 할 때 생각할 수있는 약간의 단점 main()은 원치 않는 코어 덤프가 생성 될 수 있다는 것입니다. 많은 양의 메모리를 사용하는 프로세스의 경우 이는 상당히 성 가실 수 있으며 프로그램에서 코어 덤핑 동작을 제어하려면 OS 별 함수 호출이 필요합니다. 한편, 코어 덤프 및 종료가 필요한 경우, 대신 호출 std::abort()하여 언제든지이를 달성 할 수 있고 코어 덤프없이 종료를 호출하여 언제든지 호출 할 수 있습니다 std::exit().

일화 적으로, 나는 what(): ...충돌 할 때 널리 배포 된 프로그램에 의해 인쇄되는 기본 메시지를 본 적이 없다고 생각 합니다.

C ++ 예외가 과거에 거품을 일으킨다는 강력한 논쟁은 무엇입니까 main()?

편집 : 이 사이트에는 일반적인 예외 처리 관련 질문이 많이 있습니다. 내 질문은 구체적으로 처리 할 수 ​​없어 C ++ 예외에 관한 main()것입니다. 오류 메시지가 인쇄 될 수는 있지만 즉시 중지 오류가 표시됩니다.




@gnat 내 질문은 좀 더 구체적입니다. 어떤 상황에서도 프로그래밍 언어에서 예외 처리가 아니라 처리 할 수없는 C ++ 예외에 관한 것입니다.
Praxeolitic

멀티 스레드 프로그램의 경우 상황이 더 복잡하거나 이국적 일 수 있습니다 (wrt 예외)
Basile Starynkevitch

1
Ariane 5 의 소프트웨어 사용자 는 확실히 첫 번째 출시 동안 모든 예외를 발견했으면 좋겠다 ...
Eric Towers

답변:


25

예외가 main을 넘어서게하는 한 가지 문제점은 프로그램이 std::terminate기본 동작을 호출 하는 호출로 종료된다는 것 std::abort입니다. 호출하기 전에 스택 해제가 수행 되는 경우 에만 정의 된 구현terminate 이므로 프로그램이 단일 소멸자를 호출하지 않고 종료 할 수 있습니다! 소멸자 호출로 복원해야 할 리소스가 있다면 피클 상태입니다 ...


12
소멸자 호출에 의해 실제로 복원해야 할 리소스가 있다면 피클에 있습니다 ... => (아쉽게도) C ++은 상당히 충돌하기 쉬우 며 OS가 죽이기로 결정할 수도 있습니다. 언제라도 프로그램 (예 : Unix의 OOM killer)에서 프로그램 (및 해당 환경)은 충돌을 지원하도록 조정해야합니다.
Matthieu M.

@MatthieuM. 소멸자는 충돌 중에 발생해야하는 리소스 정리에 적합하지 않다고 말하는가?
Praxeolitic

6
@Praxeolitic : 나는 모든 충돌이 스택을 풀지 않는 것은 아니라고 말하고있다 std::abort. 또한 최신 OS에서는 OS 자체가 프로세스 ID에 연결된 많은 리소스 (메모리, 파일 핸들 등)를 정리한다는 점에 주목할 가치가 있습니다. 마지막으로, "심층 방어 (Defense in Depth)"에서도 힌트를 얻었습니다. 다른 모든 프로세스는 버그 방지 기능을 갖추고 있으며 수집 한 리소스 (세션, 파일 작성을 완료하는 등)를 항상 해제 할 것으로 예상 할 수 없습니다.
Matthieu M.

3
@Praxeolitic 아니요, 소프트웨어는 정전 중에 데이터를 손상시킬 필요가 없습니다 . 이를 관리 할 수 ​​있으면 처리되지 않은 예외 후에 데이터가 손상되지 않도록 관리 할 수도 있습니다.
user253751

1
@Praxeolitic : 사실 이것은 존재합니다. WM_POWERBROADCAST메시지 를 듣고 싶을 것 입니다. 이것은 컴퓨터가 배터리 전원을 사용하는 경우에만 작동합니다 (노트북 또는 UPS를 사용하는 경우).
Brian

28

예외를 피할 수없는 주된 이유 main는 문제가 사용자에게보고되는 방식을 제어 할 수있는 모든 가능성을 상실하기 때문입니다.

오랫동안 사용하지 않거나 광범위하게 배포되지 않는 프로그램의 경우 OS가 결정한 방식에 관계없이 예기치 않은 오류가보고 될 수 있습니다 (예 : Windows에서 얼굴 오류 대화 상자 표시). ).

귀하가 판매하거나지지하는 것으로 유명한 조직이 일반 대중에게 제공하는 프로그램의 경우, 예상치 못한 문제가 발생했을 때 좋은 방법으로보고하고 가능한 한 사용자의 데이터. 반나절 동안 사용자의 작업을 잃지 않고 예기치 않게 중단되지는 않지만 일반적으로 반 정상 종료하는 것이 대안보다 비즈니스 평판에 훨씬 좋습니다.


떠나는 C ++ 예외의 기본 동작 main() 이 OS와 많은 관련이 있습니까? OS는 C ++을 전혀 모른다. 내 생각에는 컴파일러가 프로그램의 어딘가에 삽입하는 코드에 의해 결정된다는 것입니다.
Praxeolitic

5
@Praxeolitic : OS가 규칙을 설정하고 프로그램이 예기치 않게 종료 될 때 컴파일러가 이러한 규칙을 이행하기위한 코드를 생성합니다. 결론은 합리적으로 가능할 때마다 예기치 않은 프로그램 종료를 피해야한다는 것입니다.
Bart van Ingen Schenau

std C ++ 범위 내에서만 제어권을 느슨하게합니다. 이러한 "크래쉬"를 처리하는 구현 고유의 방법을 사용할 수 있어야합니다. C ++은 보통 진공 상태에서 실행되지 않습니다.
Martin Ba

레지스트리에서 가치가있는 것에 대해 얼굴 내 오류 대화 상자를 설정하거나 해제 할 수 있지만이 작업을 수행하려면 레지스트리를 제어해야합니다. 대부분의 프로그램은 키오스크 모드에서 실행되지 않습니다 (인계 됨) OS).
PerryC

11

TL; DR : 사양은 무엇을 말합니까?


기술 우회 ...

예외가 발생하고 처리기가 준비되지 않은 경우 :

  • 스택이 풀 렸는지 아닌지 정의 된 구현입니다.
  • std::terminate 기본적으로 중단되는
  • 환경 설정에 따라 중단하면 충돌 보고서가 남거나 남지 않을 수 있습니다

후자는 매우 드문 버그에 유용 할 수 있습니다 (재생하는 데 시간이 많이 걸리기 때문에).


모든 예외를 잡을지 여부는 궁극적으로 사양의 문제입니다.

  • 사용자 오류를보고하는 방법이 지정되어 있습니까? (잘못된 값, ...)
  • 기능 오류보고 방법이 지정되어 있습니까? (대상 디렉토리 누락, ...)
  • 기술 오류를보고하는 방법이 지정되어 있습니까? (어설 션 발사, ...)

모든 프로덕션 프로그램의 경우이를 지정해야하며 사양을 따라야합니다 (변경 될 수 있음).

기술 담당자 (귀하의 팀원) 만 사용할 수있는 프로그램을 신속하게 처리하려면 아무 문제가 없습니다. 필요에 따라 보고서를 받거나받지 않도록 충돌을 일으키고 환경을 설정하는 것이 좋습니다.


1
이. 결정 요인 wrt. 기본적으로 C ++의 범위를 벗어납니다.
Martin Ba

4

잡는 예외는 멋진 오류 메시지를 인쇄하거나 오류를 복구하려고 시도 할 수있는 기회를 제공합니다 (어쩌면 응용 프로그램을 다시 시작하여).

그러나 C ++에서는 예외가 발생했을 때 프로그램 상태에 대한 정보를 보유하지 않습니다. 만약 당신이 그것을 잡으면, 그러한 모든 상태는 잊혀지는 반면에, 프로그램이 충돌하게한다면, 상태는 보통 거기 있고 프로그램 덤프에서 읽을 수 있으며, 디버그하기가 더 쉽습니다.

따라서 절충안입니다.


4

당신이 중단해야한다는 것을 알게 된 순간, std::terminate더 이상 피해를 줄이기 위해 이미 전화하십시오 .

안전하게 감을 수 있다는 것을 알고 있다면 대신하십시오. 예외가 발견되지 않으면 스택 해제가 보장되지 않으므로 catch하고 다시 던지십시오.

시스템이 자체적으로 수행하는 것보다 오류를 안전하게보고 / 로그 할 수있는 경우 계속 진행하십시오.
그러나 그렇게하는 동안 실수로 문제를 악화시키지 않도록하십시오.

특정 오류에 따라 다르지만 복구 할 수없는 오류를 감지 할 때 데이터를 저장하기에는 너무 늦습니다.
어쨌든, 빠른 복구를 위해 프로그램을 작성했다면 그냥 종료하는 것이 정상적인 종료 일지라도 종료하는 가장 좋은 방법 일 수 있습니다.


1

우아하게 충돌하는 것은 대부분 좋은 일이지만 트레이드 오프가 있습니다. 때로는 충돌 하는 것이 좋습니다 . 나는 주로 디버깅에 대해 생각하고 있다고 언급해야합니다. 간단한 프로그램의 경우-여전히 유용 할 수는 있지만 매우 복잡한 프로그램 (또는 여러 복잡한 프로그램이 상호 작용하는)만큼 유용하지 않습니다.

당신은 공개적으로 충돌하고 싶지 않습니다. (이것은 피할 수 없지만 프로그램이 충돌하고 실제로 수학적으로 검증 가능한 비 충돌 프로그램은 우리가 여기서 말하는 것이 아닙니다). 데모 도중 Bill Gates BSODing을 생각해보십시오. 그럼에도 불구하고 우리는 왜 우리가 충돌했는지 같은지를 알아 내려고 시도 할 수 있습니다.

처리되지 않은 예외에 대해 로컬 크래시 덤프를 만드는 Windows 오류보고 기능을 설정했습니다. (충돌) 빌드와 관련된 심볼 파일이 있는지 궁금합니다. 흥미롭게도이 도구를 설정했기 때문에 더 많은 충돌을 원합니다 . 각 충돌에서 배우기 때문입니다. 그런 다음 버그를 수정하고 충돌을 줄일 수 있습니다.

그래서 지금은 프로그램이 맨 위로 던져져 충돌하기를 원합니다. 앞으로는 모든 예외를 정상적으로 먹고 싶을 수도 있지만, 그것이 나를 위해 효과를 발휘할 수는 없다.

관심있는 경우 로컬 크래시 덤프에 대한 자세한 내용은 여기를 참조하십시오. 사용자 모드 덤프 수집


-6

궁극적으로 main ()을 넘어 예외가 발생하면 응용 프로그램이 중단되고 내 마음에 앱이 절대로 충돌하지 않아야합니다. 한 곳에서 앱을 다운해도 괜찮다면 어딘가에서 어떻습니까? 예외 처리를 전혀 신경 쓰지 않는 이유는 무엇입니까? (Sarcasm, 실제로 이것을 제안하지는 않습니다 ...)

당신은 복구 할 수없는 오류가 발생했으며 IT에 bob에게 전자 메일로 전자 메일을 보내야한다는 것을 알려주는 우아한 메시지를 인쇄하는 전역 시도 / 잡기가있을 수 있지만 충돌은 완전히 전문적이지 않으며 받아 들일 수 없습니다. 사소한 일이며, 방금 일어난 일과 문제를 해결하는 방법에 대해 사용자에게 알릴 수 있습니다.

충돌은 엄격하게 아마추어 시간입니다.


8
그렇다면 모든 것이 올바르게 작동하는 척하고 대신 모든 영구 저장소를 횡설수설로 덮어 쓰는 것이 좋습니다.
중복 제거기

1
@ 중복 제거기 : 아니오 : 항상 예외를 잡아서 처리 할 수 ​​있습니다.
Giorgio

5
당신이 그것을 다루는 방법을 알고 있다면, 당신은 아마 일하기 전에 그것을 다룰 것입니다 main. 당신이 그것을 처리하는 방법을 모른다면, 당신이하는 척하는 것은 분명히 끔찍한 버그입니다.
중복 제거기

8
그러나 충돌은 완전히 비전문적이며 용납 할 수 없습니다 => 쓸모없는 기능으로 작업하는 데 시간을 소비하는 것은 비전문적입니다 : 충돌은 최종 사용자에게 중요한 경우에만 중요합니다. 더 경제적입니다.
Matthieu M.

Matthieu M. 실제로 오류를 기록하고 열려있는 파일을 저장하고 화면에 친숙한 메시지를 그리려면 많은 노력이 필요하다면 어떻게해야할지 모르겠습니다. 정상적으로 실패하는 것이 쓸모 없다고 생각한다면 코드에 대한 기술 지원을하는 사람에게 이야기해야 할 것입니다.
Roger Hill
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.