programing

std :: exception에서 상속해야합니까?

nasanasas 2020. 8. 25. 08:10
반응형

std :: exception에서 상속해야합니까?


적어도 하나의 신뢰할 수있는 소스 (내가 취한 C ++ 클래스)에서 C ++의 애플리케이션 별 예외 클래스가 std::exception. 이 접근 방식의 이점에 대해 잘 모르겠습니다.

C #에서 상속하는 이유 ApplicationException는 분명합니다. 유용한 메서드, 속성 및 생성자 몇 가지를 얻고 필요한 항목을 추가하거나 재정의하기 만하면됩니다. std::exception그것은 당신이 얻을 모두가 것 같다 what()당신은 단지뿐만 아니라 자신을 만들 수 있습니다 오버라이드 (override)하는 방법.

그렇다면 std::exception애플리케이션 별 예외 클래스에 대한 기본 클래스로 사용하면 어떤 이점이 있습니까? 상속하지 말아야 할 합당한 이유가 std::exception있습니까?


주요 이점은 무엇을의 정확한 유형을 알고하지 않는 클래스를 사용하여 해당 코드 throw그것에을 할 수 있지만, 단지 . 편집 : Martin과 다른 사람들이 언급했듯이 실제로 헤더 선언 된 하위 클래스 중 하나에서 파생하려고합니다 .catchstd::exception

std::exception<stdexcept>


문제 std::exception는 메시지를 수락하는 생성자가 없다는 것입니다 (표준 호환 버전에서).

결과적으로 나는 std::runtime_error. 이것은 파생 std::exception되었지만 생성자를 사용하면 호출 될 때 std::string반환 될 생성자에 C-String 또는 a 전달할 수 있습니다 .char const*what()


상속 이유는 std::exception예외에 대한 "표준"기본 클래스이므로, 예를 들어 팀의 다른 사람들이이를 예상하고 base를 잡는 것은 자연스러운 일입니다 std::exception.

편의를 찾고 있다면 생성자 std::runtime_error를 제공하는 상속을받을 수 있습니다 std::string.


나는 이전의 저자들이 int, HRESULTS, std :: string, char *, random classes ... 모든 곳에 다른 것들을 던진 대규모 코드베이스 정리에 참여한 적이 있습니다. 유형의 이름을 지정하면 아마도 어딘가에 던져졌을 것입니다. 그리고 공통 기본 클래스가 전혀 없습니다. 저를 믿으십시오. 던져진 모든 유형이 우리가 잡을 수있는 공통 기반을 가지고 있고 아무것도 지나칠 수 없다는 것을 알기 시작했을 때 상황이 훨씬 더 깔끔해졌습니다. 그러니 여러분 자신 (그리고 앞으로 여러분의 코드를 유지해야 할 사람들)에게 호의를 베푸시고 처음부터 그렇게하세요.


boost :: exception 에서 상속해야합니다 . 추가 데이터를 전달하는 더 많은 기능과 잘 알려진 방법을 제공합니다. 물론 Boost를 사용하지 않는 경우이 제안을 무시하십시오.


상속을 원하는 이유 std::exception는 그 클래스에 따라 잡힌 예외를 던질 수 있기 때문입니다.

class myException : public std::exception { ... };
try {
    ...
    throw myException();
}
catch (std::exception &theException) {
    ...
}

예,에서 파생해야합니다 std::exception.

다른 사람들은 std::exception텍스트 메시지를 전달할 수 없다는 문제 가 있다고 대답 했지만 일반적으로 던지는 시점에서 사용자 메시지 형식을 지정하는 것은 좋지 않습니다. 대신 예외 개체를 사용하여 모든 관련 정보를 catch 사이트로 전송 한 다음 사용자 친화적 인 메시지 형식을 지정할 수 있습니다.


상속에 대해 알아야 할 한 가지 문제는 객체 슬라이싱입니다. throw e;throw-expression 을 작성할 때 예외 개체라고하는 임시 개체를 초기화합니다.이 개체의 유형은 피연산자의 정적 유형에서 최상위 수준 cv 한정자를 제거하여 결정됩니다 throw. 그것은 당신이 기대하는 것이 아닐 수 있습니다. 여기에서 찾을 수있는 문제의 예 .

상속에 대한 주장이 아니라 '필수'정보 일뿐입니다.


차이점 : std :: runtime_error 대 std :: exception ()

상속 여부는 귀하 에게 달려 있습니다. 표준 std::exception및 그 하위 규격은 하나 명의 가능한 예외 계층 구조 (분할에 제안 logic_errorsubhierarchy 및 runtime_errorsubhierarchy) 및 하나의 가능한 예외 객체 인터페이스. 당신이 그것을 좋아한다면-그것을 사용하십시오. 어떤 이유로 다른 것이 필요한 경우 고유 한 예외 프레임 워크를 정의하십시오.


언어가 이미 std :: exception을 던 졌기 때문에 괜찮은 오류보고를 제공하기 위해 어쨌든 그것을 잡아야합니다. 예상치 못한 모든 예외에 대해 동일한 캐치를 사용할 수도 있습니다. 또한 예외를 발생시키는 거의 모든 라이브러리는 std :: exception에서 파생됩니다.

즉,

catch (...) {cout << "Unknown exception"; }

또는

catch (const std::exception &e) { cout << "unexpected exception " << e.what();}

그리고 두 번째 옵션은 확실히 더 좋습니다.


If all your possible exceptions derive from std::exception, your catch block can simply catch(std::exception & e) and be assured of capturing everything.

Once you've captured the exception, you can use that what method to get more information. C++ doesn't support duck-typing, so another class with a what method would require a different catch and different code to use it.


Whether to derive from any standard exception type or not is the first question. Doing so enables a single exception handler for all standard library exceptions and your own, but it also encourages such catch-them-all handlers. The problem is that one should only catch exceptions one knows how to handle. In main(), for example, catching all std::exceptions is likely a good thing if the what() string will be logged as a last resort before exiting. Elsewhere, however, it's unlikely to be a good idea.

Once you've decided whether to derive from a standard exception type or not, then the question is which should be the base. If your application doesn't need i18n, you might think that formatting a message at the call site is every bit as good as saving information and generating the message at the call site. The problem is that the formatted message may not be needed. Better to use a lazy message generation scheme -- perhaps with preallocated memory. Then, if the message is needed, it will be generated on access (and, possibly, cached in the exception object). Thus, if the message is generated when thrown, then a std::exception derivate, like std::runtime_error is needed as the base class. If the message is generated lazily, then std::exception is the appropriate base.


Another reason to sub-class exceptions is a better design aspect when working on large encapsulated systems. You can reuse it for things such as validation messages, user queries, fatal controller errors and so on. Rather than rewriting or rehooking all of your validation like messages you can simply "catch" it on the main source file, but throw the error anywhere in your entire set of classes.

e.g. A fatal exception will terminate the program, a validation error will only clear the stack and a user query will ask the end-user a question.

Doing it this way also means you can reuse the same classes but on different interfaces. e.g. A windows application can use message box, a web service will show html and reporting system will log it and so on.


Though this question is rather old and has already been answered plenty, I just want to add a note on how to do proper exception handling in C++11, since I am continually missing this in discussions about exceptions:

Use std::nested_exception and std::throw_with_nested

It is described on StackOverflow here and here, how you can get a backtrace on your exceptions inside your code without need for a debugger or cumbersome logging, by simply writing a proper exception handler which will rethrow nested exceptions.

Since you can do this with any derived exception class, you can add a lot of information to such a backtrace! You may also take a look at my MWE on GitHub, where a backtrace would look something like this:

Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"

You don't even need to subclass std::runtime_error in order to get plenty of information when an exception is thrown.

The only benefit I see in subclassing (instead of just using std::runtime_error) is that your exception handler can catch your custom exception and do something special. For example:

try
{
  // something that may throw
}
catch( const MyException & ex )
{
  // do something specialized with the
  // additional info inside MyException
}
catch( const std::exception & ex )
{
  std::cerr << ex.what() << std::endl;
}
catch( ... )
{
  std::cerr << "unknown exception!" << std::endl;
}

참고URL : https://stackoverflow.com/questions/1669514/should-i-inherit-from-stdexception

반응형