어설 션 또는 예외를 사용하여 계약에 의해 디자인합니까? [닫은]


123

계약으로 프로그래밍 할 때 함수 나 메서드는 책임을 수행하기 전에 먼저 전제 조건이 충족되었는지 확인합니다. 이러한 검사를 수행하는 가장 눈에 띄는 두 가지 방법은 by assert및 by exception입니다.

  1. assert는 디버그 모드에서만 실패합니다. 모든 개별 계약 전제 조건을 (단위) 테스트하여 실제로 실패하는지 확인하는 것이 중요합니다.
  2. 디버그 및 릴리스 모드에서 예외가 실패합니다. 테스트 된 디버그 동작이 릴리스 동작과 동일하다는 이점이 있지만 런타임 성능 저하가 발생합니다.

어느 것이 더 낫다고 생각하십니까?

여기에서 관련 질문보기


3
계약에 의한 디자인의 전체 요점은 런타임에 전제 조건을 확인할 필요가 없다는 것입니다 (그리고 틀림없이 그렇게해서는 안됩니다). 당신은 당신이 존중하는 방법의 것을, 전제 조건과 방법으로 전달하기 전에 입력을 확인 하여 계약의 끝을. 입력이 유효하지 않거나 계약 종료를 위반하는 경우 프로그램은 일반적으로 정상적인 작업 과정 (원하는)을 통해 실패합니다.
void.pointer 2012

좋은 질문이지만 (투표에서 볼 수 있듯이) 수락 된 답변을 정말로 바꿔야한다고 생각합니다!
DaveFar 2012

영원히 나중에 알지만이 질문에 실제로 C ++ 태그가 있어야합니까? 나는 다른 언어 (Delpih)에서 사용하기 위해이 답변을 찾고 있었고 동일한 규칙을 따르지 않는 예외와 주장을 특징으로하는 언어를 상상할 수 없습니다. (아직 Stack Overflow 지침을 배우고 있습니다.)
Eric G

이 응답에서 제공 되는 매우 간결한 응답 : "즉, 예외는 애플리케이션의 견고성을 해결하는 반면 어설 션은 정확성을 해결합니다."
Shmuel Levine

답변:


39

릴리스 빌드에서 assert를 비활성화하는 것은 "릴리스 빌드에서 어떤 문제도 발생하지 않을 것입니다"라고 말하는 것과 같으며, 이는 종종 그렇지 않습니다. 따라서 assert는 릴리스 빌드에서 비활성화되어서는 안됩니다. 그러나 오류가 발생할 때마다 릴리스 빌드가 충돌하는 것을 원하지 않습니까?

따라서 예외를 사용하고 잘 사용하십시오. 훌륭하고 견고한 예외 계층 구조를 사용하고 디버거에서 예외 발생에 대한 후크를 포착하고이를 포착 할 수 있는지 확인하고 릴리스 모드에서는 직접적인 충돌이 아닌 오류를 보상 할 수 있습니다. 더 안전한 방법입니다.


4
어설 션은 정확성을 확인하는 것이 적절하게 구현하는 데 비효율적이거나 비효율적 인 경우 최소한 유용합니다.
Casebash

89
주장의 요점은 오류를 수정하는 것이 아니라 프로그래머에게 경고하는 것입니다. 릴리스 빌드에서 활성화 상태를 유지하는 것은 이유 때문에 쓸모가 없습니다 . 어설 션 실행을 통해 무엇을 얻었 을까요? 개발자는 뛰어 들어 디버그 할 수 없습니다. 어설 션은 디버깅 보조 도구이며 예외를 대체하지 않습니다 (예외가 어설 션을 대체하는 것도 아닙니다). 예외는 프로그램에 오류 상태를 경고합니다. Assert는 개발자에게 경고합니다.
jalf

12
그러나 어설 션은 내부 데이터가 수정 된 후 손상되었을 때 사용해야합니다. 어설 션이 트리거되면 무언가가 / 잘못됨을 의미하기 때문에 프로그램 상태에 대한 가정을 할 수 없습니다. 어설 션이 꺼지면 데이터가 유효하다고 가정 할 수 없습니다. 그렇기 때문에 릴리스 빌드는 프로그래머에게 문제가있는 위치를 알리는 것이 아니라 프로그램이 종료되고 더 큰 문제가 발생하지 않도록해야한다고 주장해야합니다. 프로그램은 나중에 데이터를 신뢰할 수있을 때 복구를 용이하게하기 위해 할 수있는 일을해야합니다.
coppro

5
@jalf, 릴리스 빌드에서 디버거에 후크를 넣을 수는 없지만 로깅을 활용하여 개발자가 어설 션 실패와 관련된 정보를 볼 수 있습니다. 이 문서 ( martinfowler.com/ieeeSoftware/failFast.pdf )에서 Jim Shore는 "고객 사이트에서 발생하는 오류가 테스트 프로세스를 통해 발생했습니다.이를 재현하는 데 문제가있을 수 있습니다. 이러한 오류는 다음과 같습니다. 찾기가 가장 어렵고 문제를 설명하는 적절한 주장이 며칠의 노력을 절약 할 수 있습니다. "
StriplingWarrior

5
개인적으로 나는 계약 접근법에 의한 디자인에 대한 주장을 선호합니다. 예외는 방어 적이며 함수 내부에서 인수 검사를 수행합니다. 또한 dbc 전제 조건은 "작동 범위를 벗어난 값을 사용하면 작동하지 않을 것입니다."라고 말하지 않고 "정답을 제공 할 것이라고 보장하지는 않지만 여전히 할 수 있습니다"라고 말합니다. 어설 션은 개발자에게 조건 위반이있는 함수를 호출하고 있다는 피드백을 제공하지만 더 잘 안다고 느끼면 사용을 중지하지 마십시오. 위반으로 인해 예외가 발생할 수 있지만 나는 다른 것으로 생각합니다.
Matt_JD

194

경험의 법칙은 자신의 오류를 포착하려고 할 때 어설 션을 사용하고 다른 사람의 오류를 포착하려고 할 때 예외를 사용해야한다는 것입니다. 즉, 공용 API 함수에 대한 전제 조건을 확인하고 시스템 외부에있는 데이터를 가져올 때마다 예외를 사용해야합니다. 시스템 내부에있는 함수 나 데이터에 대해 어설 션을 사용해야합니다.


다른 모듈 / 애플리케이션에있는 직렬화 / 역 직렬화는 어떨까요? 독자 부분에서는 내가 잘못된 방식으로 읽으려고해서 어설 션을 사용하는 경향이있는 것은 항상 내 실수라는 것을 의미하지만, 반면에 외부 데이터가있어 결국 예고없이 형식을 변경할 수 있습니다.
Slava

데이터가 외부인 경우 예외를 사용해야합니다. 이 특별한 경우에 당신은 아마도 그 예외를 잡아서 프로그램을 죽이는 것보다 합리적인 방법으로 처리해야 할 것입니다. 또한 제 대답은 자연의 법칙이 아니라 경험 법칙입니다. :) 따라서 각각의 경우를 개별적으로 고려해야합니다.
Dima 2014 년

함수 f (int * x)에 x-> len 줄이 포함 된 경우 v가 null 인 것으로 입증 된 f (v)는 충돌이 보장됩니다. 또한 v의 이전 버전이 null로 입증되었지만 f (v)가 호출 된 것으로 입증 된 경우 논리적 모순이 있습니다. 이는 b가 궁극적으로 0으로 입증 된 a / b를 갖는 것과 동일합니다. 이상적으로 이러한 코드는 컴파일에 실패해야합니다. 가정 검사를 끄는 것은 문제가 검사 비용이 아니라면 완전히 어리 석습니다. 가정을 위반 한 위치를 모호하게하기 때문입니다. 최소한 기록되어야합니다. 어쨌든 충돌시 다시 시작 설계가 있어야합니다.
Rob

22

내가 따르는 원칙은 이것이다 : 코딩으로 상황을 현실적으로 피할 수 있다면 어설 션을 사용하십시오. 그렇지 않으면 예외를 사용하십시오.

어설 션은 계약이 준수되고 있는지 확인하기위한 것입니다. 계약은 공정해야하므로 고객은이를 준수 할 수있는 위치에 있어야합니다. 예를 들어 유효한 URL이 무엇인지에 대한 규칙이 알려져 있고 일관성이 있기 때문에 URL이 유효해야한다고 계약서에 명시 할 수 있습니다.

예외는 클라이언트와 서버 모두에서 제어 할 수없는 상황입니다. 예외는 문제가 발생했으며이를 방지하기 위해 수행 할 수있는 작업이 없음을 의미합니다. 예를 들어, 네트워크 연결은 애플리케이션 제어 범위를 벗어나므로 네트워크 오류를 방지하기 위해 수행 할 수있는 작업이 없습니다.

어설 션 / 예외 구분이 실제로 그것에 대해 생각하는 가장 좋은 방법이 아니라는 점을 추가하고 싶습니다. 당신이 정말로 생각하고 싶은 것은 계약과 그것이 어떻게 시행 될 수 있는지에 관한 것입니다. 위의 URL 예제에서 가장 좋은 방법은 URL을 캡슐화하고 Null이거나 유효한 URL 인 클래스를 갖는 것입니다. 계약을 시행하는 URL로 문자열을 변환하는 것이며 유효하지 않은 경우 예외가 발생합니다. URL 매개 변수가있는 메서드는 String 매개 변수가있는 메서드와 URL을 지정하는 어설 션이있는 메서드보다 훨씬 명확합니다.


6

어설 션은 개발자가 잘못한 것을 포착하기위한 것입니다 (자신뿐만 아니라 팀의 다른 개발자도). 사용자 실수가이 조건을 생성 할 수있는 것이 합리적이라면 예외 여야합니다.

마찬가지로 결과에 대해 생각하십시오. 어설 션은 일반적으로 앱을 종료합니다. 조건이 복구 될 수 있다는 현실적인 기대가있는 경우 예외를 사용해야합니다.

문제가 할 수 있다면 다른 한편으로는, 단지 프로그래머 오류로 인해 수 가능한 한 빨리 그것에 대해 알고 싶어하기 때문에 다음 어설를 사용합니다. 예외가 포착되어 처리 될 수 있으며 이에 대해 알 수 없습니다. 그리고 그렇습니다. 릴리스 코드에서 어설 션을 비활성화해야합니다. 앱이 복구 될 가능성이 가장 적을 경우 복구하기를 원하기 때문입니다. 프로그램의 상태가 심각하게 손상 되더라도 사용자는 작업을 저장할 수 있습니다.


5

"디버그 모드에서만 어설 션이 실패한다"는 것은 정확히 사실이 아닙니다.

에서 소프트웨어 건설, 제 2 판 객체 지향 버트 랜드 마이어, 릴리스 모드에서 전제 조건을 확인하기위한 개방 저자 잎 문에 의해. 이 경우 어설 션이 실패하면 어설 션 위반 예외가 발생합니다! 이 경우 상황에서 복구 할 수 없습니다. 유용한 작업을 수행 할 수 있으며 오류 보고서를 자동으로 생성하고 경우에 따라 애플리케이션을 다시 시작하는 것입니다.

그이면의 동기는 전제 조건이 일반적으로 불변 및 사후 조건보다 테스트 비용이 저렴하고 경우에 따라 릴리스 빌드의 정확성과 "안전성"이 속도보다 더 중요하다는 것입니다. 즉, 많은 응용 프로그램에서 속도는 문제가되지 않지만 견고성 (프로그램의 동작이 올바르지 않을 때, 즉 계약이 깨졌을 때 안전한 방식으로 동작하는 프로그램의 능력)이 중요합니다.

항상 사전 조건 검사를 활성화 상태로 두어야합니까? 때에 따라 다르지. 그것은 당신에게 달려 있습니다. 보편적 인 대답은 없습니다. 은행 용 소프트웨어를 만드는 경우, $ 1,000 대신 $ 1,000,000을 이체하는 것보다 경고 메시지와 함께 실행을 중단하는 것이 더 나을 수 있습니다. 하지만 게임을 프로그래밍한다면 어떨까요? 당신이 얻을 수있는 모든 속도가 필요할 수도 있고, 만약 누군가가 (활성화되지 않았기 때문에) 전제 조건이 포착하지 못한 버그로 인해 10 점 대신 1000 점을 얻는다면 운이 좋을 것입니다.

두 경우 모두 이상적으로는 테스트 중에 해당 버그를 포착해야하며 어설 션을 활성화 한 상태에서 테스트의 상당 부분을 수행해야합니다. 여기서 논의되는 것은 불완전한 테스트로 인해 이전에 감지되지 않은 시나리오에서 프로덕션 코드에서 전제 조건이 실패하는 드문 경우에 대한 최상의 정책이 무엇인지입니다.

요약하면, 어설 션을 사용할 수 있으며 최소한 Eiffel에서 활성화 상태로두면 예외를 자동으로 가져올 수 있습니다 . C ++에서도 똑같이하려면 직접 입력해야합니다.

참고 항목 : 언제 어설 션이 프로덕션 코드에 유지되어야합니까?


1
당신의 요점은 확실히 유효합니다. 소위는 특정 언어를 지정하지 않은 - C #의 경우 표준 어설 System.Diagnostics.Debug.Assert입니다 않습니다 만 디버그 빌드에 실패하고, 릴리스 빌드에서 컴파일시에 제거됩니다.
yoyo

2

comp.lang.c ++. moderated의 릴리스 빌드에서 어설 션 활성화 / 비활성화에 관한 큰 스레드 가있었습니다 . 몇 주만 있으면 이에 대한 의견이 얼마나 다양한 지 알 수 있습니다. :)

coppro 와는 달리 , 릴리스 빌드에서 어설 션을 비활성화 할 수 있는지 확실하지 않다면 어설 션이 아니어야한다고 생각합니다. 어설 션은 프로그램 불변이 깨지는 것을 방지하기위한 것입니다. 이 경우 코드 클라이언트에 관한 한 두 가지 가능한 결과 중 하나가 있습니다.

  1. 일종의 OS 유형 오류로 사망하여 중단 호출이 발생합니다. (어설 션없이)
  2. 중단하라는 직접 호출을 통해 죽습니다. (어설 션 포함)

사용자에게 차이는 없지만 어설 션이 코드가 실패하지 않는 대부분의 실행에 존재하는 코드에 불필요한 성능 비용을 추가 할 수 있습니다.

질문에 대한 답은 실제로 API 클라이언트가 누구인지에 따라 훨씬 더 많이 달라집니다. API를 제공하는 라이브러리를 작성하는 경우 고객에게 API를 잘못 사용했음을 알리는 일종의 메커니즘이 필요합니다. 두 가지 버전의 라이브러리를 제공하지 않는 한 (하나는 어설 션이 있고 하나는없는) assert는 적절한 선택이 아닐 것입니다.

그러나 개인적으로이 경우에도 예외가 있을지 확신 할 수 없습니다. 예외는 적절한 형태의 복구가 발생할 수있는 경우에 더 적합합니다. 예를 들어 메모리를 할당하려고 할 수 있습니다. 'std :: bad_alloc'예외를 포착하면 메모리를 확보하고 다시 시도 할 수 있습니다.


2

나는 여기에 문제의 상태에 대한 나의 견해를 설명했다 : 객체의 내부 상태를 어떻게 검증합니까? . 일반적으로 귀하의 주장을 주장하고 다른 사람의 위반에 대해 던집니다. 릴리스 빌드에서 어설 션을 비활성화하려면 다음을 수행 할 수 있습니다.

  • 값 비싼 검사에 대한 어설 션 비활성화 (예 : 범위 주문 여부 확인)
  • 사소한 검사를 활성화 상태로 유지 (널 포인터 또는 부울 값 검사 등)

물론 릴리스 빌드에서 실패한 어설 션 및 포착되지 않은 예외는 디버그 빌드 (std :: abort를 호출 할 수 있음)와는 다른 방식으로 처리되어야합니다. 오류 로그를 어딘가에 (파일에) 기록하고 고객에게 내부 오류가 발생했음을 알립니다. 고객이 로그 파일을 보낼 수 있습니다.


1

디자인 타임과 런타임 오류의 차이에 대해 질문하고 있습니다.

어설 션은 '헤이 프로그래머, 이건 고장났다'알림이며, 버그가 발생했을 때 알아 차리지 못했을 버그를 상기시키기 위해 존재합니다.

예외는 'hey user, somethings gone wrong'알림입니다.

따라서 모든 버그를 제거 할 수 있다고 생각되면 예외 만 사용하십시오. 할 수 없다고 생각한다면 ..... 예외를 사용하십시오. 물론 디버그 어설 션을 사용하여 예외 수를 줄일 수 있습니다.

많은 전제 조건이 사용자가 제공하는 데이터라는 것을 잊지 마십시오. 따라서 사용자에게 데이터가 좋지 않다는 것을 알리는 좋은 방법이 필요합니다. 이를 위해 호출 스택의 오류 데이터를 그가 상호 작용하는 비트로 반환해야하는 경우가 많습니다. 어설 션은 유용하지 않을 것입니다. 앱이 n 계층이면 두 배입니다.

마지막으로, 저는 둘 다 사용하지 않습니다. 오류 코드는 정기적으로 발생할 것이라고 생각하는 오류보다 훨씬 우수합니다. :)


0

나는 두 번째 것을 선호합니다. 테스트가 제대로 실행되었을 수 있지만 Murphy 는 예기치 않은 일이 잘못 될 것이라고 말합니다. 따라서 실제 잘못된 메서드 호출에서 예외가 발생하는 대신 NullPointerException (또는 이에 상응하는) 10 스택 프레임 깊이를 추적하게됩니다.


0

이전 답변이 정확합니다. 공용 API 함수에 예외를 사용하십시오. 이 규칙을 구부릴 수있는 유일한 경우는 검사 비용이 계산적으로 비쌀 때입니다. 이 경우 어설 션에 넣을 수 있습니다 .

해당 전제 조건을 위반할 가능성이 있다고 생각되면 예외로 유지하거나 전제 조건을 리팩토링하십시오.


0

둘 다 사용해야합니다. Assert는 개발자의 편의를위한 것입니다. 예외는 런타임 중에 놓쳤거나 예상하지 못한 것을 포착합니다.

나는 평범한 오래된 주장 대신 glib의 오류보고 기능을 좋아했습니다 . 그들은 assert 문처럼 동작하지만 프로그램을 중지하는 대신 값을 반환하고 프로그램을 계속합니다. 놀랍게도 잘 작동하며, 함수가 "무엇을해야하는지"를 반환하지 않을 때 프로그램의 나머지 부분에 어떤 일이 발생하는지 확인할 수 있습니다. 충돌이 발생하면 오류 검사가 다른 곳에서 느슨하다는 것을 알고 있습니다.

마지막 프로젝트에서 이러한 스타일의 함수를 사용하여 전제 조건 검사를 구현했으며 그중 하나가 실패하면 스택 추적을 로그 파일에 인쇄하지만 계속 실행했습니다. 디버그 빌드를 실행할 때 다른 사람들이 문제를 겪을 때 많은 디버깅 시간을 절약했습니다.

#ifdef DEBUG
#define RETURN_IF_FAIL(expr)      do {                      \
 if (!(expr))                                           \
 {                                                      \
     fprintf(stderr,                                        \
        "file %s: line %d (%s): precondition `%s' failed.", \
        __FILE__,                                           \
        __LINE__,                                           \
        __PRETTY_FUNCTION__,                                \
        #expr);                                             \
     ::print_stack_trace(2);                                \
     return;                                                \
 };               } while(0)
#define RETURN_VAL_IF_FAIL(expr, val)  do {                         \
 if (!(expr))                                                   \
 {                                                              \
    fprintf(stderr,                                             \
        "file %s: line %d (%s): precondition `%s' failed.",     \
        __FILE__,                                               \
        __LINE__,                                               \
        __PRETTY_FUNCTION__,                                    \
        #expr);                                                 \
     ::print_stack_trace(2);                                    \
     return val;                                                \
 };               } while(0)
#else
#define RETURN_IF_FAIL(expr)
#define RETURN_VAL_IF_FAIL(expr, val)
#endif

인수의 런타임 검사가 필요한 경우 다음을 수행합니다.

char *doSomething(char *ptr)
{
    RETURN_VAL_IF_FAIL(ptr != NULL, NULL);  // same as assert(ptr != NULL), but returns NULL if it fails.
                                            // Goes away when debug off.

    if( ptr != NULL )
    {
       ...
    }

    return ptr;
}

나는 OP 질문에서 C ++와 관련된 것을 본 적이 없다고 생각합니다. 나는 그것이 당신의 대답에 포함되어서는 안된다고 생각합니다.
ForceMagic 2013-08-07

@ForceMagic :이 질문에 제가이 답변을 게시했을 때 2008 년에 C ++ 태그가 있었는데 실제로 C ++ 태그는 불과 5 시간 전에 제거되었습니다. 그럼에도 불구하고 코드는 언어 독립적 인 개념을 보여줍니다.
indiv

0

나는 여기에 내 자신의 견해로 다른 몇 가지 답변을 종합하려고했습니다.

프로덕션에서 비활성화하려는 경우에는 어설 션을 사용하고이를 그대로 두십시오. 프로덕션에서는 비활성화하지만 개발에서는 비활성화하는 유일한 이유는 프로그램 속도를 높이는 것입니다. 대부분의 경우이 속도 향상은 중요하지 않지만 때로는 코드가 시간이 중요하거나 테스트 비용이 많이 듭니다. 코드가 미션 크리티컬 한 경우 속도 저하에도 불구하고 예외가 최선일 수 있습니다.

실제 복구 가능성이있는 경우 어설 션이 복구되도록 설계되지 않았으므로 예외를 사용하십시오. 예를 들어, 코드는 프로그래밍 오류에서 복구하도록 설계되지 않았지만 네트워크 장애 또는 잠긴 파일과 같은 요인으로부터 복구하도록 설계되었습니다. 프로그래머의 통제 밖에 있다는 이유로 오류를 예외로 처리해서는 안됩니다. 오히려 이러한 오류의 예측 가능성은 코딩 실수와 비교하여 복구에 더 적합합니다.

어설 션을 디버그하는 것이 더 쉽다는 주장 : 적절하게 명명 된 예외의 스택 추적은 어설 션만큼 읽기 쉽습니다. 좋은 코드는 특정 유형의 예외 만 포착해야하므로 포착으로 인해 예외가 눈에 띄지 않게되어서는 안됩니다. 그러나 Java는 때때로 모든 예외를 포착하도록 강요한다고 생각합니다.


0

내가보기에 경험의 규칙은 assert 식을 사용하여 내부 오류와 외부 오류에 대한 예외를 찾는 것입니다. 여기 에서 Greg의 다음 토론을 통해 많은 이점을 얻을 수 있습니다 .

Assert 표현식은 프로그램 논리 자체의 오류 또는 해당 구현의 오류와 같은 프로그래밍 오류를 찾는 데 사용됩니다. 어설 션 조건은 프로그램이 정의 된 상태로 남아 있는지 확인합니다. "정의 된 상태"는 기본적으로 프로그램의 가정과 일치하는 상태입니다. 프로그램에 대한 "정의 된 상태"는 "이상적인 상태", "일반적인 상태"또는 "유용한 상태"일 필요는 없지만 나중에 중요한 점에 대해 더 자세히 설명합니다.

어설 션이 프로그램에 어떻게 맞는지 이해하려면 포인터를 역 참조하려는 C ++ 프로그램의 루틴을 고려하십시오. 이제 루틴은 역 참조 전에 포인터가 NULL인지 여부를 테스트해야합니까, 아니면 포인터가 NULL이 아니라고 주장한 다음 계속해서 역 참조해야합니까?

대부분의 개발자는 어설 션을 추가하고 어설 션을 추가하고 어설 션 된 조건이 실패 할 경우 충돌하지 않도록 포인터에서 NULL 값을 확인하기를 원할 것이라고 생각합니다. 표면적으로는 테스트와 확인을 모두 수행하는 것이 가장 현명한 결정으로 보일 수 있습니다.

어설 션 된 조건과 달리 프로그램의 오류 처리 (예외)는 프로그램의 오류가 아니라 프로그램이 환경에서 얻은 입력을 나타냅니다. 이는 종종 사용자가 암호를 입력하지 않고 계정에 로그인을 시도하는 것과 같이 누군가의 "오류"입니다. 그리고 오류로 인해 프로그램 작업이 성공적으로 완료되지 않을 수 있지만 프로그램 실패는 없습니다. 프로그램이 외부 오류 (사용자의 오류)로 인해 암호없이 사용자 로그인에 실패합니다. 상황이 다르고 사용자가 올바른 암호를 입력했는데 프로그램이 암호를 인식하지 못한 경우 결과는 여전히 동일하지만 실패는 이제 프로그램에 속합니다.

오류 처리 (예외)의 목적은 두 가지입니다. 첫 번째는 사용자 (또는 다른 클라이언트)에게 프로그램 입력 오류가 감지되었으며 그 의미를 알리는 것입니다. 두 번째 목표는 오류가 감지 된 후 애플리케이션을 잘 정의 된 상태로 복원하는 것입니다. 이 상황에서 프로그램 자체는 오류가 아닙니다. 물론, 프로그램은 비 이상적인 상태이거나 아무 것도 유용하지 않지만 프로그래밍 오류가없는 상태 일 수 있습니다. 반대로 오류 복구 상태는 프로그램 설계 상 예상되는 상태이므로 프로그램이 처리 할 수있는 상태입니다.

추신 : 비슷한 질문 인 Exception Vs Assertion 을 확인해보십시오 .


-1

이 질문 도 참조하십시오 :

어떤 경우에는 릴리스를 위해 빌드 할 때 어설 션이 비활성화됩니다. 이를 제어 할 수 없을 수도 있으므로 (그렇지 않으면 어설 션을 사용하여 빌드 할 수 있습니다) 이렇게하는 것이 좋습니다.

입력 값을 "수정"할 때 발생하는 문제는 호출자가 예상 한 것을 얻지 못한다는 것입니다. 이로 인해 프로그램의 완전히 다른 부분에서 문제가 발생하거나 충돌이 발생하여 디버깅이 악몽이 될 수 있습니다.

나는 보통 if 문에서 예외를 던져서 그들이 비활성화 된 경우 어설 션의 역할을 인수합니다.

assert(value>0);
if(value<=0) throw new ArgumentOutOfRangeException("value");
//do stuff
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.