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


15

첫 번째 '심각한'C ++ 라이브러리를 디자인하는 동안 나 자신에게 묻습니다.

예외를 파생시키는 것이 좋은 스타일입니까, std::exception자손입니까?!

읽은 후에도

아직 확실하지 않습니다. 일반적인 관행 (아마도 좋지는 않지만) 관행 외에도 라이브러리 사용자 std::exception는 라이브러리 구현에서 표준 라이브러리 함수가 실패한 경우에만 라이브러리 함수가 throw 되고 이에 대해 아무것도 할 수 없다고 가정합니다. 그러나 여전히 응용 프로그램 코드를 작성할 때 매우 편리하며 IMHO는을 던지는 것이 std::runtime_error좋습니다. 또한 내 사용자는 what()또는 코드 와 같이 정의 된 최소 인터페이스에 의존 할 수도 있습니다 .

예를 들어, 내 사용자는 잘못된 인수를 제공합니다.를 던지는 것보다 더 편리한 std::invalid_argument것은 무엇입니까? 그래서 std :: exception의 일반적인 사용법과 결합하여 다른 코드에서 볼 수 있습니다 std::exception.

생각?


잘 모르겠습니다. 당신이 상속해서 std::exception의미하지 않는다 당신이 던져std::exception. 또한, std::runtime_error상속을하지 std::exception처음부터, 그리고 what()방법에서 유래 std::exception하지 std::runtime_error. 그리고와 같은 일반적인 예외를 발생시키는 대신 자신 만의 예외 클래스를 만들어야합니다 std::runtime_error.
Vincent Savard

3
차이점은 내 lib_foo_exception클래스가에서 파생 될 때 std::exception라이브러리 사용자는 라이브러리 라이브러리 lib_foo_exception만 잡는 것 std::exception외에도 잡기만한다는 것입니다. 따라서 라이브러리 예외 루트 클래스를 std :: exception에서 상속 해야하는지 묻습니다 .
Superlokkus

3
@LightnessRacesinOrbit "... 이외에도 몇 가지 방법이 lib_foo_exception있습니까?" 상속을 std::exception통해 catch(std::exception)OR로 할 수 있습니다 catch(lib_foo_exception). 에서 파생없이 std::exception, 당신은 그것을 잡을 것입니다 경우에만 경우 로, catch(lib_foo_exception).
Superlokkus

2
@Superlokkus : 우리는 무시 catch(...)합니다. 이 언어는 고려중인 사례 (및 "오작동"라이브러리)를 허용하지만 현대적인 모범 사례는 아닙니다.
Monica와의 가벼움 경주

1
C ++에서 많은 예외 처리 디자인은 catch사용자가 더 많은 작업을 모델링하는 더 거칠고 일반적인 사이트 및 더 성가신 트랜잭션 을 장려하는 경향이 있습니다. std::exception&예를 들어, 일반적인 잡기 개념을 홍보하지 않는 언어와 비교하면 try/catch매우 구체적인 오류와 관련된 중개 블록 이있는 코드가 더 많기 때문에 예외 처리의 일반성이 다소 떨어집니다. 수동 오류 처리 및 발생할 수있는 모든 개별 오류에 대해 더욱 강조합니다.

답변:


29

모든 예외는에서 상속되어야합니다 std::exception.

예를 들어,을 호출해야하고 ComplexOperationThatCouldFailABunchOfWays()예외를 처리하려고 한다고 가정하십시오 . 모든 것이에서 상속되면 std::exception쉽습니다. 단일 catch블록 만 필요하며 what()세부 정보를 얻기위한 표준 인터페이스 ( )가 있습니다.

try {
    ComplexOperationThatCouldFailABunchOfWays();
} catch (std::exception& e) {
    cerr << e.what() << endl;
}

예외가에서 상속되지 않으면 std::exception훨씬 더 나빠집니다.

try {
    ComplexOperationThatCouldFailABunchOfWays();
} catch (std::exception& e) {
    cerr << e.what() << endl;
} catch (Exception& e) {
    cerr << e.Message << endl;
} catch (framework_exception& e) {
    cerr << e.Details() << endl;
}

던질 것인지 runtime_error또는 던질 invalid_argument자신의 std::exception서브 클래스를 만들지 에 관한 것 : 내 경험상 다른 오류와 다르게 특정 유형의 오류를 처리해야 할 때마다 (즉, 별도의 catch블록이 필요할 때마다) 새로운 서브 클래스를 도입하는 것이 좋습니다 .

  • 생각할 수있는 모든 유형의 오류에 대해 새로운 예외 서브 클래스를 도입하면 개별적으로 처리 할 필요가 없더라도 많은 클래스 확산이 추가됩니다.
  • 기존 서브 클래스를 재사용하여 특정 무언가를 의미하는 경우 (즉, 여기runtime_error던져진 것이 일반 런타임 오류와 다른 것을 의미하는 경우) 기존 서브 클래스의 다른 용도와 충돌 할 위험이 있습니다.
  • 내가하면 하지 않는 구체적으로 오류를 처리해야하고, 내가 던지고있어 그 오류가 정확히 기존의 표준 라이브러리의 오류 중 하나 (예 : 일치하는 경우 invalid_argument), 그때는 기존의 클래스를 다시 사용합니다. 이 경우 새 클래스를 추가해도 큰 이점이 없습니다. (C ++ 핵심 지침은 여기에 동의하지 않습니다. 항상 자신의 클래스를 사용하는 것이 좋습니다.)

C ++ 핵심 가이드 라인은 자세한 설명과 예제가 있습니다.


그 모든 앰퍼샌드! C ++는 이상하다.
SuperJedi224

2
@ SuperJedi224와 다른 모든 편지들! 영어가 이상합니다.
johannes

이 근거는 이해가되지 않습니다. 이 아닌 것은 catch (...)(문자 그대로의 생략 부호와 함께)에 대한인가?
Maxpm

1
@Maxpm catch (...)은 던져진 것에 대해 아무것도 할 필요가없는 경우에만 유용합니다 . 예를 들어 특정 오류 메시지를 표시하거나 기록하는 등의 작업을 수행하려는 경우 그 내용이 무엇인지 알아야합니다.
Josh Kelley

9

라이브러리 사용자는 라이브러리 구현에서 표준 라이브러리 함수가 실패했을 때만 라이브러리 함수가 std :: exceptions를 throw하고 아무것도 할 수 없다고 가정합니다.

그것은 잘못된 가정입니다.

"일반적인"사용을 위해 표준 예외 유형이 제공됩니다. 표준 라이브러리 에서만 사용 하도록 설계되지 않았습니다 .

예, 모든 것을 궁극적으로에서 상속 받으십시오 std::exception. 종종 std::runtime_error또는 에서 상속을받는 경우가 있습니다 std::logic_error. 구현하는 예외 클래스에 적합한 것이 무엇이든간에.

이것은 물론 주관적이다. 몇몇 인기있는 라이브러리는 표준 예외 유형을 완전히 무시하고 아마도 표준 라이브러리에서 라이브러리를 분리 할 것이다. 개인적으로 나는 이것이 매우 이기적이라고 생각합니다! 예외를 잡기가 훨씬 어려워집니다.

개인적으로 말하면, 나는 종종 그냥 던져서 std::runtime_error처리합니다. 그러나 그것은 예외 클래스를 만드는 것이 얼마나 세분화되는지에 대한 토론으로 들어가고 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.