program tip

C ++에서 assert ()를 사용하고 있습니까?

radiobox 2020. 9. 21. 07:32
반응형

C ++에서 assert ()를 사용하고 있습니까?


릴리스 빌드의 성능에 영향을주지 않고 디버깅을 더 쉽게하기 위해 내 C ++ 코드에 많은 어설 션을 추가하는 경향이 있습니다. 이제는 assertC ++ 메커니즘을 염두에 두지 않고 설계된 순수 C 매크로입니다.

반면에 C ++는을 정의하는데 std::logic_error, 이는 프로그램의 논리 (따라서 이름)에 오류가있는 경우에 throw됩니다. 인스턴스를 던지는 것은 assert.

문제이다 assert하고 abort, 소멸자를 호출하지 않고 즉시 프로그램을 종료 때문에 예외를 발생하는 반면 수동 런타임 불필요한 비용을 추가 정리 스킵 둘. 이 문제를 해결하는 한 가지 방법 SAFE_ASSERT은 C와 동일하게 작동하지만 실패시 예외를 던지는 자체 assertion 매크로를 만드는 것 입니다.

이 문제에 대한 세 가지 의견을 생각할 수 있습니다.

  • C의 주장을 고수하십시오. 프로그램이 즉시 종료되기 때문에 변경 사항이 올바르게 풀 렸는지 여부는 중요하지 않습니다. 또한 #defineC ++에서 s를 사용 하는 것도 나쁘다.
  • 예외를 던지고 main ()에서 포착하십시오 . 코드가 프로그램의 모든 상태에서 소멸자를 건너 뛰도록 허용하는 것은 나쁜 습관이며 어떤 대가를 치르더라도 피해야하며, terminate () 호출도 마찬가지입니다. 예외가 발생하면이를 포착해야합니다.
  • 예외를 발생시키고 프로그램을 종료 시키십시오. 프로그램을 종료하는 예외는 괜찮으며으로 인해 NDEBUG릴리스 빌드에서는 절대 발생하지 않습니다. 캐칭은 불필요하며 내부 코드의 구현 세부 정보를 main().

이 문제에 대한 확실한 답이 있습니까? 전문적인 참조가 있습니까?

편집 됨 : 소멸자를 건너 뛰는 것은 물론 정의되지 않은 동작이 아닙니다.


어설 션은 C ++ 코드에서 전적으로 적절합니다. 예외 및 기타 오류 처리 메커니즘은 실제로 어설 션과 동일한 용도로 사용되지 않습니다.

오류 처리는 오류를 복구하거나 사용자에게 잘보고 할 수있는 가능성이있는 경우를위한 것입니다. 예를 들어 입력 파일을 읽는 중에 오류가 발생하면 이에 대해 조치를 취할 수 있습니다. 오류는 버그로 인해 발생할 수 있지만 주어진 입력에 대한 적절한 출력 일 수도 있습니다.

어설 션은 API가 정상적으로 확인되지 않을 때 API의 요구 사항이 충족되는지 확인하거나 개발자가 구성에 의해 보장된다고 생각하는 사항을 확인하는 것과 같은 작업입니다. 예를 들어 알고리즘에 정렬 된 입력이 필요한 경우 일반적으로 확인하지 않지만 디버그 빌드가 해당 종류의 버그에 플래그를 지정하도록 확인하는 어설 션이있을 수 있습니다. 어설 션은 항상 잘못 작동하는 프로그램을 나타내야합니다.


비정상 종료로 인해 문제가 발생할 수있는 프로그램을 작성하는 경우 어설 션을 피하는 것이 좋습니다. C ++ 언어 측면에서 엄격하게 정의되지 않은 동작은 여기에서 그러한 문제로 인정되지 않습니다. 어설 션을 친 것은 아마도 이미 정의되지 않은 동작의 결과이거나 일부 정리가 제대로 작동하지 못하게 할 수있는 다른 요구 사항의 위반 일 수 있기 때문입니다.

또한 예외와 관련하여 주장을 구현하면 주장의 목적과 모순되는 경우에도 잠재적으로 포착되어 '처리'될 수 있습니다.


  • 어설 션은 디버깅 을위한 것 입니다. 배송 된 코드의 사용자는 코드를 볼 수 없습니다. 어설 션이 적중되면 코드를 수정해야합니다.

  • 예외는 예외적 인 상황 입니다. 하나가 발생하면 사용자는 원하는 작업을 수행 할 수 없지만 다른 곳에서 다시 시작할 수 있습니다.

  • 오류 처리는 정상적인 프로그램 흐름을위한 것입니다. 예를 들어, 사용자에게 숫자를 입력하라는 메시지를 표시하고 구문 분석 할 수없는 것을 얻는다면 이는 정상적인 현상입니다 . 사용자 입력은 사용자가 제어 할 수없고 항상 가능한 모든 상황을 당연히 처리해야하기 때문입니다. (예 : 유효한 입력이있을 때까지 반복하여 중간에 "죄송합니다. 다시 시도"라고 말합니다.)


어설 션은 일부 메서드 실행 전후의 내부 상태와 같은 내부 구현 불변을 확인하는 데 사용할 수 있습니다. 어설 션이 실패하면 실제로 프로그램의 논리가 손상되어 복구 할 수 없음을 의미합니다. 이 경우 최선의 방법은 사용자에게 예외를 전달하지 않고 가능한 한 빨리 중단하는 것입니다. (적어도 Linux에서는) 어설 션에 대해 정말 좋은 점은 프로세스 종료의 결과로 코어 덤프가 생성되므로 스택 추적 및 변수를 쉽게 조사 할 수 있다는 것입니다. 이것은 예외 메시지보다 논리 실패를 이해하는 데 훨씬 유용합니다.


모든 abort ()로 인해 소멸자를 실행하지 않는 것은 정의되지 않은 동작이 아닙니다!

그렇다면 호출하는 std::terminate()것도 정의되지 않은 동작 이 될 것입니다. 그렇다면이를 제공하는 데있어 중요한 점은 무엇일까요?

assert() 어설 션은 오류 처리를위한 것이 아니라 프로그램을 즉시 중단하기위한 것입니다.


IMHO, 주장은 위반하면 다른 모든 것을 말도 안되게 만드는 조건을 확인하기위한 것입니다. 따라서 당신은 그들로부터 회복 할 수 없거나 오히려 회복은 무관합니다.

두 가지 범주로 그룹화합니다.

  • 개발자 죄 (예 : 음수 값을 반환하는 확률 함수) :

float 확률 () {return -1.0; }

assert (probability ()> 0.0)

  • 기계가 고장났습니다 (예 : 프로그램을 실행하는 기계가 매우 잘못되었습니다) :

int x = 1;

assert (x> 0);

이것들은 모두 사소한 예이지만 현실과 그리 멀지 않습니다. 예를 들어 벡터와 함께 사용하기 위해 음의 인덱스를 반환하는 순진한 알고리즘을 생각해보십시오. 또는 맞춤형 하드웨어에 내장 된 프로그램. 아니면 오히려 이 일어나기 때문에 .

And if there is such development mistakes you should not be confident about any recovering or error handling mechanism implemented. The same applies for hardware errors.

참고URL : https://stackoverflow.com/questions/12062365/is-using-assert-in-c-bad-practice

반응형