문제

정보가 부족하기 때문에 끈을 던지지 말아야한다고 들었습니다. 예외를 던지기위한 좋은 관행은 무엇입니까? 기본 예외 클래스를 상속합니까? 예외가 많거나 적은 것이 있습니까? MyExceptionClass & 또는 Const MyExceptionClass를 수행합니까? 등도 등도 나는 예외가 파괴자에게 버려서는 안된다는 것을 알고 있습니다.

계약에 따라 디자인을 이해하고 예외를 던질 때를 이해한다고 덧붙였습니다. 예외를 어떻게 던져야하는지 묻습니다.

도움이 되었습니까?

해결책

제 생각에는 "약속"을 유지할 수 없다면 함수는 "계약"을 위반 해야하는 경우 예외를 제기해야합니다. 함수의 서명 (이름 및 매개 변수)이 계약을 결정합니다.

이 두 멤버 기능이 주어지면 :

const Apple* FindApple(const wchar_t* name) const;
const Apple& GetApple(const wchar_t* name) const;

이러한 기능의 이름과 반환 값은 나에게 findapple 이 기능은 올바른 사과를 찾을 수 없을 때 NULL을 완벽하게 반환 할 수 있지만 GetApple 당신은 사과가 돌아올 것을 기대하고 있습니다. 두 번째 기능이 약속을 지킬 수 없다면 예외를 던져야합니다.

예외는 함수가 이러한 조건을보고하는 다른 방법이없는 탁월한 조건을위한 것입니다. 약속의 일부로 만들기로 결정한 경우 (읽기 : 기능 서명) 예외를 던지지 않고 해당 조건을보고 할 수 있습니다.

경우에 유의하십시오 findapple, "올바른 애플을 찾지 못한다"는 조건을 처리하는 방법을 결정하는 것은 발신자에게 달려 있습니다. 더 이상 예외적 인 조건이 아니기 때문입니다.

당신은 모든 예외를 피하려고 시도 할 수도 있지만, 가능한 모든 예외적 인 조건을 설명해야하며 대신 발신자에게 부담을 둔다는 것을 의미합니다. 발신자는 "오류 조건"을 확인해야합니다.

궁극적으로 예외는 처리해야하지만 발신자만이 처리해야합니다. 유용한 방식으로 특정 조건을 처리하는 방법을 알고 있습니다.. 그리고 가장 넓은 해석에서 이것을 의미합니다. 포기하는 서비스는 나중에 다시 시도 할 것입니다. 유용한 오류 메시지를 제공하는 UI, "oops"화면을 제공하지만 훌륭하게 복구하는 웹 앱 등을 제공합니다. .

데이브

다른 팁

한 가지 기본 사항은 예외적 인 상황에 대해서만 예외를 예약하는 것입니다. 흐름 제어를 위해 사용하지 마십시오. 예를 들어, "파일 찾기"는 예외가되어서는 안됩니다. 파일이 어떤 것도 아닌 한 오류 코드 또는 반환 값이어야합니다. ~ 해야 하다 존재, 예를 들어 구성 파일). 그러나 처리하는 동안 파일이 갑자기 사라지면 예외를 던지는 것이 좋습니다.

예외가 드물게 사용되면 더 깊은 레이어에서 이해할 수없는 텍스트 예외를받지 않기 위해 코드를 Try-Catch -spaghetti로 전환 할 필요가 없습니다.

표준 예외를 사용하십시오! 특정 오류가있는 경우 리턴 값으로 피하십시오. 만약 너라면 가지다 예외를 사용하려면 예외에서 상속되는 사용자 정의 예외를 정의하고 사용자 정의 메시지를 만듭니다.

때로는 오류 코드를 반환 할 수 없을 수도 있습니다. 오류 상황이 발생했을 때의 정확한 컨텍스트가 필요한 경우 (예 : 오류 상태 3 레벨을 전파 해야하는 경우 컨텍스트가 느슨합니다.

이 상황에서 커스텀 클래스는 최상의 솔루션입니다. 나는이 접근법을 사용하여 내 자신의 인라인 클래스를 정의합니다 (그것들을위한 .cpp는 없습니다; h) : 예를 들어 :

class DeviceException {
    ;
}

class DeviceIOException: public DeviceException {
    DeviceIOException(std::string msg, int errorCode);
}

등.

그런 다음 유형과 내부에 포함 된 정보별로 예외를 판단/행동 할 수 있습니다.

나는 항상 그것이 어디에서 발생했는지와 그 일이 발생하게 된 것에 대한 메시지로 예외를 던집니다.

throw NException("Foo::Bar", "Mungulator cause a stack overflow!");

그런 다음이 문자열을 MessageBox에서 사용할 수 있습니다.

나는 항상 따라 잡는다

catch (NException& ex) { ... }

Windows를 실행하는 경우 오류 값을 전달하고 기능이 오류 메시지를 도출 할 수 있습니다. 이것의 가장 좋은 예는 Jeffrey Richter의 C/C ++를 통한 Windows.

포인터를 던지는 것은 아마도 좋지 않을 것입니다. 그것은 던져진 대상의 소유권을 복잡하게 만들기 때문에 아마도 좋은 일이 아닙니다. 클래스 유형 예외는 예외의 이유에 대한 자세한 정보를 포함 할 수 있기 때문에 기본보다 낫다.

클래스 또는 클래스 계층 구조를 사용하려면 몇 가지 점이 있습니다.

  1. 예외 객체의 카피 생성자와 소멸자 모두 예외를 던지지 않아야합니다. 그들이 당신이 프로그램을한다면, 프로그램은 즉시 종료됩니다. (ISO 15.5/1)

  2. 예외 객체에 기본 클래스가있는 경우 공개 상속을 사용하십시오.
    기본 클래스가 인 경우 핸들러는 기본 클래스로 파생 된 것에 대해서만 선택됩니다. 얻기 쉬운. (ISO 15.3/3)

  3. 마지막으로, (모든 예외 유형의 경우) 던져진 표현 자체가 예외를 발생시킬 수는 없도록합니다.

예를 들어:

class Ex {
public:
  Ex(int i) 
  : m_i (i)
  {
    if (i > 10) {
      throw "Exception value out of range";
    }
  }

  int m_i;
};


void foo (bool b) {
  if (! b) {
     // 'b' is false this is bad - throw an exception
     throw Ex(20);    // Ooops - throw's a string, not an Ex
  }
}

항상 std :: 예외에서 파생 된 예외 클래스를 던져야합니다. 이를 통해 인터페이스에 특정 일관성을 유지하고 이러한 방법이나 기능의 클라이언트에 더 많은 유연성을 제공합니다. 예를 들어 캐치 모든 핸들러를 추가하려면 추가 할 수 있습니다.

catch(std::exception& e)
차단하고 완료하십시오. (던질 수있는 모든 코드를 제어하지 않으면 종종 그 문제를 해결할 수 없습니다).

나는 표준 (예 : std :: runtime_error)에 의해 제공된 예외 만 던지는 경향이 있지만 핸들러에 추가 세분화를 제공하려면 std :: 예외에서 자신의 것을 자유롭게 도출해야합니다. 보다 C ++ FAQ 라이트.

또한, 임시를 던져서 참조로 잡아야합니다 (CATCTOR가 캐치 사이트에서 호출되는 것을 피하기 위해). 누가 기억을 정리 해야하는지 불분명하기 때문에 던지는 포인터도 눈살을 찌푸립니다. C ++ FAQ 라이트 이것도 다루어집니다.

현재 프로젝트의 경우 메인 프로그램 루프가 취할 수있는 적절한 조치에 대해 생각했습니다. 기본 프로그램은 XML 메시지를 수락하고 정보를 데이터베이스에 저장합니다 (간에 상당한 양의 처리가 포함).

  1. 입력을 잘못 나타내는 데이터 오류. 적절한 조치는 메시지를 로그 디렉토리에 저장하지만 처리하지 않는 것입니다.
  2. 일부 하위 구성 요소 (입력 큐, SQL 데이터베이스, JNI 라이브러리)를 나타내는 인프라 오류가 오작동합니다. 몇 분 동안 잠을 자고 다시 연결하십시오.
  3. 일부 측면 구성을 나타내는 구성 오류는 작동하지 않습니다. 프로그램을 종료하십시오.

첫 번째 항목은 데이터 점검이 메소드 인터페이스의 일부로 간주 되었기 때문에 확인 된 예외입니다. 기본 루프는 하위 구성 요소의 구현을 알 수 없으므로 다른 것들은 검사되지 않습니다.

다른 개발자가 다운 스트림을 사용하는 구성 요소에서 예외를 제외하고 있다면, 큰 호의를 베풀고 std :: 예외에서 항상 자신의 예외 클래스 (실제로 표준 예외를 사용하여 CF가 필요하다면)를 도출하십시오. 모든 비용을 피하십시오. ints, hresults, char*, std :: string ...와 같은 혐오가 있습니다.

이미 말한 것처럼 예외적 인 상황에만 사용하십시오.

항상 사용자가 예외를 던지지 않도록하는 방법을 제공합니다. 방법이 있다면 이와 같이 무언가 잘못되면 던질 것입니다.

public void DoSomethingWithFile() {
    if(!File.Exists(..))
        throw new FileNotFoundException();
}

사용자가 호출 할 수있는 다른 방법을 제공합니다.

public bool CanDoSomething() {
    return File.Exists(..);
}

이런 식으로 발신자는 원한다면 예외를 피할 수 있습니다. 무언가 잘못되면 주저하지 말고 "빠르게 실패"하지만 항상 예외 경로를 제공하십시오.

또한 예외 클래스 계층 구조를 평평하게 유지하고 InvalidStateException 및 ArgumentNullexCpetion과 같은 표준 예외를 살펴보십시오.

다음은 거의 모든 리소스가 필요한 예외를 던지는 간단한 예입니다.

class DivisionError {};
class Division
{
public:
    float Divide(float x, float y) throw(DivisionError)
    {
        float result = 0;
        if(y != 0)
            result = x/y;
        else
            throw DivisionError();
        return result;
    }
};

int main()
{
    Division d;
    try
    {
        d.Divide(10,0);
    }
    catch(DivisionError)
    {
        /*...error handling...*/
    }
}

던져진 빈 클래스는 자원을 취하지 않거나 거의 ...

C ++ FAQ에서 17.12] 무엇을 던져야합니까?:

일반적으로 내장이 아닌 물체를 던지는 것이 가장 좋습니다. 가능하면 (궁극적으로) std::exception 수업.

...그리고

가장 일반적인 관행은 임시를 던지는 것입니다. (다음의 예 참조)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top