2010-12-29 3 views
7

가끔씩 나는 몇 년 동안 가지고 있었던 코딩 패턴에 주목하고 그것이 나를 긴장하게 만든다. 나는 특별한 문제가 없지만 왜 내가 그 패턴을 채택했는지에 대해 충분히 기억하지 못하고 어떤 패턴이 어떤 반 패턴과 일치하는 것으로 보인다. 최근에 내 코드의 일부가 예외를 사용하는 방식에 대해 WRT가 발생했습니다.제 C++ catch 절, 예외 클래스 패밀리 및 파괴 제정신을 사용하고 있습니까?

걱정스러운 점은 매개 변수를 함수로 처리하는 것과 비슷한 방식으로 "참조로"예외를 처리하는 경우입니다. 한 가지 이유는 예외 클래스의 상속 계층 구조를 가질 수 있고 응용 프로그램에 따라보다 일반적이고보다 정확한 catch 유형을 지정할 수 있기 때문입니다. 내가 클래스 인스턴스가 함수 내 (드로우의 일부로서) 구성되어 것으로 나타났습니다하지만 p_Exception를 통해 (참조되기 때문에 예를 들어, 나는

class widget_error {}; 
class widget_error_all_wibbly : public widget_error {}; 
class widget_error_all_wobbly : public widget_error {}; 

void wibbly_widget() 
{ 
    throw widget_error_all_wibbly(); 
} 

void wobbly_widget() 
{ 
    throw widget_error_all_wobbly(); 
} 

void call_unknown_widget (void (*p_widget)()) 
{ 
    try 
    { 
    p_widget(); 
    } 
    catch (const widget_error &p_exception) 
    { 
    // Catches either widget_error_all_wibbly or 
    // widget_error_all_wobbly, or a plain widget_error if that 
    // is ever thrown by anything. 
    } 
} 

지금 나를 걱정입니다 ... 정의 할 수 있습니다 catch 절 "매개 변수")를 호출합니다. 이것은 일반적으로 안티 패턴입니다 - 로컬 변수에 대한 참조 또는 포인터 또는 함수 내에서 생성 된 임시이지만 함수가 종료 될 때 전달되는 변수는 일반적으로/임시 변수 인 로컬 변수가 소멸되고 메모리가 해제되므로 매달린 참조/포인터입니다. 함수가 종료 될 때

일부 빠른 테스트는 위의 throw는 아마도 괜찮을 것이라고 제안합니다. 즉, throw 절에서 생성 된 인스턴스는 함수가 종료 될 때 파괴되지 않지만 catch 블록이 처리 할 때 destructed됩니다. catch 블록이 rethrows하지 않는 한 예외가 발생하면 다음 catch 블록이이 작업을 수행합니다.

하나 또는 두 개의 컴파일러에서 테스트를 실행하면 표준이 말하는 것을 증명할 수 없기 때문에 내 경험에 의하면 내 상식이기 때문에 종종 언어가 보장하는 것과 다릅니다.

이렇게 - 예외를 처리하는 (참조 유형을 사용하여 예외를 잡는)이 패턴의 패턴이 안전합니까? 아니면 다른 일을해야합니까 ...

  • (일시적 일 때처럼 보이는) 무언가에 대한 참조 대신 힙 할당 된 인스턴스에 대한 포인터를 잡아서 (명시 적으로 삭제) 포인터를 잡아서 (명시 적으로 삭제)?
  • 스마트 포인터 클래스 사용?
  • "pass-by-value"catch 절을 사용하고 하나의 catch 절이있는 계층 구조에서 예외 클래스를 catch 할 수 없다는 것을 받아들입니까?
  • 내가 생각하지 못했던 것?
+2

[가상 상속 사용] (http://www.boost.org/community/error_handling.html). – ybungalobill

+1

@ybungalobill - 농담 인 줄 알았는데 링크를 읽었습니다. 흥미로운 점. – Steve314

답변

9

괜찮습니다. 실제로 상수 참조에 의해 예외를 잡는 것이 좋습니다 (포인터를 잡는 것이 좋지 않습니다). 값을 잡으면 불필요한 사본이 생성됩니다. 컴파일러는 예외 (및 파기)를 올바르게 처리 할 수있을만큼 똑똑합니다. catch 블록 외부에서 예외 참조를 사용하지 마십시오 .-)

사실, 제가 자주하는 일은 std :: runtime_error (std :: exception에서 상속)의 계층 구조입니다. 그런 다음 .what()을 사용할 수 있으며 더 많은 예외를 처리하는 동안 catch 블록을 더 적게 사용합니다.

+0

+1을 사용하면 유용한 답변을 얻을 수 있습니다. 나는 가장 유용하게 찢겨졌지만 마침내 이것을 받아들이기로 결정했다. – Steve314

6

이 패턴은 확실히 안전합니다.

발생 된 개체의 수명을 연장하는 특별한 규칙이 있습니다. 실제로 처리되는 한 존재하며 마지막으로 처리 할 블록이 끝날 때까지 존재한다는 것이 보장됩니다.

예를 들어 std::exception에서 사용자 지정 예외를 파생시키고 하나의 catch 절을 사용하여 다양한 예외에서 오류 메시지를 인쇄 할 수 있도록 참조 함수로 what() 멤버 함수를 재정의하고 참조로 catch합니다.

4

예. 여태까지는 그런대로 잘됐다.

개인적으로 모든 예외 calsses의 기초로 std :: runtime_error를 사용합니다. 오류 메시지 등을 처리합니다.

더 많은 예외를 선언하지 마십시오. 실제로 잡히거나 고칠 수있는 것에 대해서만 예외를 정의하십시오. 잡히거나 고칠 수없는 것들에 대해보다 일반적인 예외를 사용하십시오.

예 : 라이브러리를 개발하면 A. 그러면 std :: runtime_error에서 파생 된 AException이 생깁니다. 이 예외는 라이브러리의 모든 일반 예외에 사용됩니다. 라이브러리의 사용자가 실제로 예외를 잡아 (수정 또는 완화) 할 수있는 특정 예외의 경우 AException에서 파생 된 특정 예외를 작성합니다 (단, 예외로 수행 할 수있는 작업이있는 경우에만).