2010-01-07 3 views
42

예외를 잡는 세 가지 방법이 있다는 것을 알게되었는데 그 차이점은 무엇입니까?C++에서 포인터로 예외를 catch

1) 값으로 캐치;

2) 참조로 캐치;

3) 포인터로 포착;

값으로 catch가 객체의 사본 두 개를 호출한다는 것을 알고, 참조로 catch하면 하나만 호출됩니다. 그러면 포인터로 잡는 것은 어떨까요? 언제 포인터로 catch를 사용할 수 있습니까? 객체를 던지는 것 외에도 객체에 포인터를 던질 수 있습니까?

class A {} 

void f() { 

    A *p = new A(); 
     throw p; 


} 
+6

__not__ 포인터로 예외를 잡을 수 있습니다. 포인터가되는 예외를 잡을 수 있습니다. 문제는 A와 A *가 완전히 다른 두 가지 유형이라는 것입니다. A에 포인터를 던지면 값이나 참조 만 잡을 수 있습니다. 그러나 A *입니다. 값으로 참조하거나 A를 참조하지 않습니다. –

답변

70

권장되는 방법은 참조에 의해 값과 캐치에 의해 던져하는 것입니다.

귀하의 예제 코드는 포인터를 던졌습니다. 캐치 사이트에서 메모리를 관리해야하므로 나쁜 생각입니다.

포인터를 가져야한다고 생각되면 shared_ptr과 같은 스마트 포인터를 사용하십시오.

어쨌든 Herb Sutter와 Alexei Alexandrescu는 내가 그 말을 바꾼 C++ 코딩 표준 책에서 이것을 잘 설명합니다.

C++ Coding Standards: Throw by Value, Catch by Reference을 참조하십시오.

+12

그리고 던지고있는 이유가 메모리 부족으로 인해 버리면 새 객체를 할당하려고 시도하는 것이 도움이되지 않습니다. –

+3

A에 포인터를 던지거나 A를 할당 할 수 있는지 여부에 따라 std :: bad_alloc을 발생시킵니다. 그래서 적어도 뭔가를 던질 것입니다 ... –

+0

'const std :: runtime_error err; 'const std :: runtime_error &'에서'std :: runtime_error &'로의 변환이 없다는 가정하에 나는 정답을 맞 춥니 다. 따라서 런타임에 의해 잡히고 아마도 프로그램이 중단됩니다. 내가 맞습니까? –

1

포인터로 예외를 포착/throw하는 데는 실제로 좋은 시나리오가 아닙니다. C++ 의미론을 사용하면이를 허용하지만 대개 임시 예외 또는 문자열 객체를 던질 때 유용하기 때문에 그리 유용하지는 않습니다.

그러나 일부 라이브러리 (Boost.Graph는 이것을 수행합니다.)는 매우 재귀 함수에서 호출자에게 반환 값을 전달하기 위해 throw를 사용합니다. 이와 같은 상황에서 반환 값은 포인터 일 수 있으므로 포인터를 던지는 것이 의미가 있습니다.

14

캐치는 일반적인 할당 호환성 규칙을 따릅니다. 즉, 값을 던진 경우 값 또는 참조로 catch 할 수 있지만 포인터로는 catch 할 수 없습니다. 포인터를 던지면 포인터 (또는 포인터 참조)로만 포인터를 잡을 수 있습니다.

그러나 실제로는 포인터를 버리는 것이 의미가 없으며 메모리 관리 문제 만 일으 킵니다. 따라서 일반적으로 Gregory가 설명한대로 값으로 throw하고 참조 번호을 catch해야합니다.

4

Microsoft의 MFC는 포인터로 포인터를 사용하지만 try와 catch가 제대로 구현되기 전에 컴파일러와의 호환성을위한 것이라고 생각합니다. 원래 그들은 TRY 및 CATCH 매크로를 사용하여 시뮬레이션했습니다. 각 예외는 CException에서 파생됩니다. CException에는 객체를 삭제해야하는지 여부를 결정하는 메서드가 있습니다.

현대적인 예외 디자인에 대해서는 권장하지 않습니다. 참조로 잡아 당길 수있는 방법입니다.

2

어떤 유형의 객체라도 본질적으로 던질 수는 있지만 실제로 이렇게하면 얻을 수있는 것이 거의 없습니다. 동적 할당은 주로 객체의 수명이 자동 할당과 맞지 않을 때 유용합니다. 즉, 평생 프로그램을 정상적인 프로그램 범위와 독립적으로 유지하려는 경우에 유용합니다.

그러나 예외 개체의 경우에는 실제로 그렇게 이해가되지 않습니다. 예외 객체는 일반적으로 예외 핸들러 내부에서만 사용되므로 예외에 대한 (마지막) 핸들러를 종료 할 때 예외 객체가 파괴되기를 원할 것입니다.

일반적으로 예외 처리 코드를 매우 간단하게 유지하기를 원합니다. 예를 들어 무료 저장소/힙이 고갈되었거나 손상되었다고보고하려는 경우 예외 개체를 지쳐 버린/손상된 무료 저장소/힙에서 할당하려고하면 일반적으로 잘 작동하지 않습니다.