2010-04-10 4 views
14

나는 예외를 던지기위한 모든 요구에 대해 std::exception의 서브 클래스를 작성해야한다고 확신합니다. 이제 what 메서드를 재정의하는 방법을 살펴 보겠습니다.std :: exception의`what`에서 동적 문자열을 반환하십시오.

내가 직면하고있는 상황은 what 문자열이 동적으로 반환되면 매우 편리 할 것입니다. 일부 코드 조각은 예를 들어 XML 파일을 구문 분석하고 위치 또는 행 번호를 오류 메시지에 추가하면 유용합니다.

나는 Boost Exception handling guidelines을 따르려고합니다. 내가 좋아하는 것 무엇

은 알고 :

  • what는 포수가 문자열을 해제하지 않을 가능성이 암시 const char *을 반환합니다. 그래서 결과를 저장하기 위해 다른 장소가 필요합니다.하지만 그 위치는 어디입니까? (thread-safety가 필요합니다.)

  • whatthrow()의 서명이 포함되어 있습니다. 내 what이 던지는 것을 막을 수는 있지만,이 방법은 너무 동적 인 것은 아닙니다. what이 올바른 장소가 아니면 대신이 위치를 어디에서해야합니까? 내가 지금까지 들어 왔 답변에서


는,이 예외에 문자열을 저장하는 것입니다 달성 할 수있는 유일한 방법처럼 보인다. 부스트 가이드 라인은 이것에 반대하는 것이 좋습니다. 이것은 나를 혼란스럽게합니다. 왜냐하면 std::runtime_error이 그렇게하기 때문입니다.

C- 문자열을 사용하는 경우에도 정적으로 크기가 조정 된 버퍼를 사용해야하거나 메모리 관리가 실패 할 수도 있습니다. (이것이 실제로 실제로 std::string의 복사 생성자에서 잘못 될 수있는 유일한 것인지 궁금합니다. 즉, 동적으로 할당 된 C 문자열을 사용하지 못하게 될 것입니다.)

다른 옵션이 있습니까? 왼쪽?

+1

부스트 가이드 라인 포인트가 추가되어 부적절한 경우 다시 편집하십시오. –

답변

15

내 예외 클래스는 일반적으로 생성자하지만 아무것도 이러한 라인을 따라 보이지 않는 :

class MyEx: public std::runtime_error 
{ 
public: 
    MyEx(const std::string& msg, int line): 
     std::runtime_error(msg + " on line " + boost::lexical_cast<string>(line)) 
    {} 
}; 

임의 예를 들어,하지만 what() 메시지를 관리하는 처리의 기본 클래스입니다.

그러나 원하는 경우 생성자 본문에 메시지를 넣은 후에 예외 객체의 기본 부분 만 지정할 수도 있습니다.

#include <stdexcept> 
#include <string> 
#include <sstream> 

class MyEx: public std::runtime_error 
{ 
public: 
    MyEx(const std::string& msg, int line): 
     std::runtime_error("") 
    { 
     std::stringstream ss; 
     ss << msg << " on line " << line; 
     static_cast<std::runtime_error&>(*this) = std::runtime_error(ss.str()); 
    } 
}; 

#include <iostream> 
int main() 
{ 
    try { 
     throw MyEx("Evil code", __LINE__); 
    } 
    catch (const std::exception& e) { 
     std::cout << e.what() << '\n'; 
    } 
} 

그러나, 부스트의 가이드 라인에 대한, 아마도 당신은 수치 데이터 (위치 및 라인)가 가장 다른 방법을 통해 숫자로 제공 될 수 있다는 점에주의해야한다. 지침은 what() 메시지에 대해 덜 걱정한다고 말합니다.

+0

더 걱정 스럽지만'std :: runtime_error'는 문자열을 저장합니다. 그래서 표준 라이브러리 자체가 부스트 가이드 라인과 모순이됩니까? –

+0

부스트 작성자는 문자열의 서식 지정이나 복사가 (메모리 부족?) 오류를 발생시킬 수있는 (원격) 가능성에 대해 우려하고 있습니다. 예외 객체는 던져 질 때마다 항상 복사됩니다. –

3

글쎄, 문제가 없으면 단순히 파생 된 예외 클래스의 생성자를 구현하여 what()에서 반환 할 문자열의 형식을 지정할 수 있습니다. 소멸자에서 사용하는 버퍼를 해제하십시오.

+0

이것은 gf의 대답과 비슷하거나 일반적인 C- 문자열을 의미합니까? 런타임이 값을 따라 예외를 전달하기 때문에 문자열이 catch 이전에 해제 될 수 있습니까? –

+0

잘 모르겠습니다. 어떤 문자열이 해제 될 수 있습니까? 포인터를 저장하는 예외 클래스에 복사 생성자를 구현해야합니다. –

6

부스트의 지침은 예외 객체를 복사하면 또 다른 예외가 발생하고 what() 문자열은 강력하거나 신뢰할 수있는 도구가 아님을 가정합니다. 이것은 다양한 환경에서 폭넓게 사용되는 라이브러리를 작성하는 경우에 유효한 사항입니다. 예외가 어떻게 사용될 것인지 더 잘 알고 있다면, 이러한 우려가 아무런 이유없이 합리적인지 아니면 많은 고민인지 판단 할 수 있습니다. 프로그래밍은 모두 일련의 절충점에 관한 것이므로 Boost 개발자에게 타당한 절충안이 적용되지 않을 수도 있습니다.

1

나는 원래의 질문에 대해 가장 정확하고 완전한 대답이라고 기술적으로 생각하기 때문에 UncleBens의 답변을 수락합니다.

실제로 참조 할 수있는 다른 솔루션을 선택하여 what을 사용하지 않았습니다.

struct Exception : public virtual std::exception 
{ 
    virtual const char* what() const throw() 
    { 
    try { 
     return typeid(this).name(); 
    } 
    catch (const std::exception& e) { 
     return "<unknown exception>"; 
    } 
    } 

    // Extended description; may throw. 
    virtual void describe(std::ostream& out) const = 0; 
}; 

은 기본적으로 그냥 다른 곳에서는 그것으로 귀찮게하지 않고 찾을 수있는 가장 의미있는 일에 what을 작성 : 나는 기본 예외 클래스를 사용하기위한 지금 가지고있는 코드를 리팩토링했습니다. 나는이 운임이 어떻게되는지 볼 것입니다.

2

이 문제를 해결하는 가장 좋은 방법은 steal the code입니다.

나를위한 계몽 포인트는 그 문자열이 mute 수 있다는 것을 깨닫고 있었다. 당시 마법처럼 보였습니다. Mark는이 일에 큰 일을했습니다.

+0

그것은 좋은 기사입니다. 예외 클래스 자체에 메시지 건물을 위임하는 유일한 차이점과 함께 Mark와 마찬가지로 스트림을 사용하여 종료했습니다. 이 모든 후, 내 방법의 단점은 내 목표를 달성하기 위해 여전히 오류 코드가 필요할 수도 있다는 것입니다. Mark의 방법의 단점은 부스트 ​​(Boost)가 말한 것처럼'terminate()'할 수 있다는 것이다. –

+0

나는 예외가 쓸모 없다는 개념에 동의하지 않는 유일한 사람인가? – MFH

관련 문제