릴리스 빌드에 어설 션이 있어야합니다


20

assertC ++에서 기본 동작은 릴리스 빌드에서 아무것도하지 않는 것입니다. 나는 이것이 성능상의 이유로 수행되고 사용자가 불쾌한 오류 메시지를 보지 못하게하는 것으로 가정합니다.

그러나, 나는 assert불이 붙었을 때 비활성화되었지만 비활성화 된 상황 은 응용 프로그램이 아마도 불일치로 인해 더 나쁜 방식으로 충돌 할 수 있기 때문에 훨씬 더 번거 롭다고 주장합니다 .

또한, 나를위한 성능 인수는 측정 가능한 문제 일 때만 계산됩니다. assert내 코드의 대부분 은보다 복잡하지 않습니다.

assert(ptr != nullptr);

대부분의 코드에 작은 영향을 미칩니다.

이로 인해 질문이 나옵니다. 릴리스 빌드에서 어설 션 (특정 구현이 아닌 개념을 의미)이 활성화되어야합니까? 왜 그렇지 않습니까?

이 질문은 릴리스 빌드에서 ( #undef _NDEBUG자체 정의 된 어설 션 구현 과 같은 또는 어설 션 사용) 어설 션을 활성화하는 방법에 관한 것이 아닙니다 . 또한 타사 / 표준 라이브러리 코드에서 어설 션을 활성화하는 것이 아니라 내가 제어하는 ​​코드에서 어설 션을 활성화하는 것에 관한 것입니다.


건강 관리 시장의 글로벌 플레이어가 고객 사이트에 병원 정보 시스템의 디버그 버전을 설치 한 것을 알고 있습니다. 또한 C ++ 디버그 라이브러리를 설치하기 위해 Microsoft와 특별 계약을 체결했습니다. 글쎄, 그들의 제품의 품질은 ...
Bernhard Hiller

2
가는 옛말있다 "주장을 제거하면 조금 항구에서 연습에 생명 재킷을 입고, 그러나 뒤에 생명 재킷을 떠나처럼 때 대양에 대한 당신의 배 잎" ( wiki.c2.com/?AssertionsAsDefensiveProgramming ) . 기본적으로 릴리스 빌드에서 개인적으로 사용하도록 설정합니다. 불행하게도, 이러한 행위는 C ++ 세계에서 매우 일반적인 아니지만, 적어도 유명한 C에서 ++ 베테랑 제임스 간제는 항상 릴리스의 주장을 유지에 찬성 주장하는 데 사용되는 빌드 : stackoverflow.com/a/12162195/3313064
크리스찬 해클

답변:


20

클래식 assert은 C ++이 아닌 이전 표준 C 라이브러리의 도구입니다. 적어도 이전 버전과의 호환성으로 인해 C ++에서 여전히 사용할 수 있습니다.

C 표준 라이브러리에 대한 정확한 타임 라인은 없지만 assertK & R C가 시작된 직후 (1978 년경)에 사용 가능하다고 확신 합니다. 고전적인 C에서는 강력한 프로그램을 작성하기 위해 C ++보다 NULL 포인터 테스트 및 배열 범위 검사를 더 자주 수행해야합니다. 포인터 대신 참조 및 / 또는 스마트 포인터를 사용하면 NULL 포인터 테스트를 피할 수 있으며 std::vector, 배열 범위 검사는 종종 필요하지 않습니다. 더욱이 1980 년의 성과는 오늘날보다 훨씬 중요했습니다. "assert"가 기본적으로 디버그 빌드에서만 활성화되도록 설계된 이유 일 것입니다.

또한 프로덕션 코드에서 실제 오류 처리를 위해 일부 조건 또는 불변을 테스트하고 조건이 충족되지 않으면 프로그램을 중단시키는 기능은 대부분의 경우 충분히 유연하지 않습니다. 프로그램을 실행하고 오류를 관찰하는 사람은 일반적으로 어떤 일이 발생하는지 분석 할 수있는 디버거를 가지고 있기 때문에 디버깅에는 문제가 없을 것입니다. 그러나 생산 코드의 경우 현명한 솔루션은 다음과 같은 기능 또는 메커니즘이어야합니다.

  • 일부 조건을 테스트하고 조건이 실패한 범위에서 실행을 중지합니다.

  • 상태가 유지되지 않는 경우 명확한 오류 메시지를 제공합니다

  • 외부 스코프가 오류 메시지를 가져 와서 특정 통신 채널로 출력하도록합니다. 이 채널은 stderr, 표준 로그 파일, GUI 프로그램의 메시지 상자, 일반적인 오류 처리 콜백, 네트워크 가능 오류 채널 또는 특정 소프트웨어에 가장 적합한 것입니다.

  • 사례 별 기반의 외부 범위를 통해 프로그램이 정상적으로 종료되어야하는지 또는 계속해야하는지 결정할 수 있습니다.

(물론, 충족되지 않은 조건의 경우 프로그램을 즉시 종료하는 것이 유일하게 합리적인 옵션이지만 상황에 따라 디버그 빌드뿐만 아니라 릴리스 빌드에서도 발생해야합니다).

클래식 assert은이 기능을 제공하지 않기 때문에 릴리스 빌드에 적합하지 않습니다. 릴리스 빌드가 프로덕션에 배포 된 것으로 가정합니다.

이제 C 표준 라이브러리에 이러한 종류의 유연성을 제공하는 기능이나 메커니즘이없는 이유를 물을 수 있습니다. 실제로 C ++에는 이러한 모든 기능 (및 그 이상)이있는 표준 메커니즘이 있으며 예외 라고 합니다.

그러나 C에서는 프로그래밍 언어의 일부로 예외가 없기 때문에 언급 된 모든 기능으로 오류 처리를위한 좋은 범용 표준 메커니즘을 구현하기가 어렵습니다. 따라서 대부분의 C 프로그램에는 리턴 코드 또는 "goto"또는 "long jumps"또는 이들을 혼합 한 자체 오류 처리 메커니즘이 있습니다. 이것들은 종종 특정 종류의 프로그램에는 적합하지만 C 표준 라이브러리에 적합 할 정도로 "일반적인 목적"은 아닙니다.


아, C 유산에 대해 완전히 잊어 버렸습니다 #include <cassert>. 그것은 지금 완전히 의미가 있습니다.
아무도

1
나는이 전체 답변에 완전히 동의하지 않습니다. 애플리케이션이 소스 코드에 버그가 있음을 발견했을 때 예외를 던지는 것이 Java와 같은 언어의 최후의 수단이지만 C ++에서는 그러한 상황에서 프로그램을 즉시 종료해야합니다. 당신은 원인이 스택 언 와인딩하지 않으려는 어떤 추가 작업은 그 시점에서 실행될 수 있습니다. 버그가있는 프로그램은 파일, 데이터베이스 또는 네트워크 소켓에 손상된 데이터를 쓸 수 있습니다. 최대한 빨리 충돌하고 외부 메커니즘으로 프로세스를 다시 시작해야합니다.
Christian Hackl

1
@ChristianHackl : 프로그램 종료가 유일하게 실행 가능한 옵션 인 상황에 동의하지만 릴리스 모드에서도 발생해야 assert하며 이것에 대한 잘못된 도구이기도합니다 (예외를 던지면 실제로 잘못된 반응 일 수도 있음) ). 그러나 실제로 assertC ++에서 오늘 예외를 사용하는 C의 많은 테스트에도 실제로 사용되었다고 확신 합니다.
Doc Brown

15

릴리스에서 어설 션을 사용하려는 경우 어설트가 잘못된 작업을 수행하도록 요청했습니다.

주장의 요점은 릴리스에서 사용할 수 없다는 것입니다. 이를 통해 발판 코드가되어야하는 코드로 개발하는 동안 변이체를 테스트 할 수 있습니다. 릴리스 전에 제거해야하는 코드입니다.

릴리스 중에도 테스트해야한다고 느끼는 것이 있으면 테스트하는 코드를 작성하십시오. If throw구조는 아주 잘 작동합니다. 다른 던지기와 다른 것을 말하고 싶다면 간단히 말하고 싶은 것을 나타내는 설명 적 예외를 사용하십시오.

어설 션 사용 방법을 변경할 수있는 것은 아닙니다. 그렇게한다고해서 유용한 정보를 얻지 못하고 기대에 부응하고 어떤 주장을했는지 분명하게 알 수있는 방법은 없습니다. 릴리스에서 비활성 인 테스트를 추가하십시오.

저는 특정 assert 구현이 아니라 주장 개념에 대해 이야기하고 있습니다. 나는 독자들을 혐오하거나 혼란스럽게하고 싶지 않다. 나는 그것이 왜 이런 식으로 처음인지 물었다. 추가 release_assert가없는 이유는 무엇입니까? 필요가 없습니까? 출시시 주장이 무효화되는 이유는 무엇입니까? - 아무도

왜 relase_assert가 없습니까? 주장은 생산에 충분하지 않기 때문에 솔직히. 그렇습니다. 그러나 그 요구를 충족시키는 것은 없습니다. 자기 자신을 디자인 할 수 있습니다. 기계적으로 throwIf 함수는 부울과 예외가 필요합니다. 그리고 그것은 당신의 필요에 맞을 수도 있습니다. 그러나 실제로 디자인을 제한하고 있습니다. 그렇기 때문에 언어 라이브러리에 예외 던지기 시스템과 같은 멍청한 주장이 없다는 것이 놀랍지 않습니다. 확실히 당신이 할 수있는 것은 아닙니다. 다른 사람이 있습니다 . 그러나 일이 잘못되는 경우를 다루는 것은 대부분의 프로그램에서 작업의 80 %입니다. 그리고 지금까지 아무도 모든 솔루션에 적합한 단일 크기를 보여주지 않았습니다. 이러한 경우를 효과적으로 다루는 것은 복잡해질 수 있습니다. 우리가 필요로하지 않는 통조림 release_assert 시스템을 가지고 있다면 더 해를 끼친다 고 생각합니다. 이 문제에 대해 생각할 필요가없는 좋은 추상화를 요구하고 있습니다. 나도 하나 원하지만 아직 우리처럼 보이지는 않습니다.

릴리스에서 어설 션이 비활성화 된 이유는 무엇입니까? 비계 코드 시대의 높이에서 주장이 만들어졌습니다. 우리가 제거해야하는 코드는 프로덕션 환경에서는 원하지 않지만 버그를 찾는 데 도움이되도록 개발 단계에서 실행되기를 원했기 때문에 제거해야했습니다. 어설 션은 if (DEBUG)패턴을 깔끔하게 대체 하여 코드를 그대로두고 비활성화시킵니다. 이것은 테스트 코드를 프로덕션 코드와 분리하는 주요 방법으로 단위 테스트가 시작되기 이전입니다. 어설트는 오늘날에도 여전히 유닛 테스트 전문가들에 의해 사용되고 있지만 기대치를 명확하게하고 유닛 테스트보다 여전히 더 나은 사례를 다루기 위해 사용됩니다.

프로덕션 환경에서 디버깅 코드를 남겨 두지 않는 이유는 무엇입니까? 생산 코드는 회사를 당황하게 만들 필요가 없으므로 하드 드라이브를 포맷하지 말고 데이터베이스를 손상시키지 말고 대통령 위협 이메일을 보내지 마십시오. 간단히 말해서 걱정할 필요가없는 안전한 장소에 디버깅 코드를 작성할 수있는 것이 좋습니다.


2
내 질문은 다음과 같습니다. 왜 출시 전에이 코드를 제거해야합니까? 검사는 성능 저하가 많지 않고 실패하면 더 직접적인 오류 메시지를 선호하는 문제가 있습니다. 어설 션 대신 예외를 사용하면 어떤 이점이 있습니까? 아마도 관련없는 코드가 그것을 원하지 않을 것입니다 catch(...).
아무도

2
@Nobody assert가 아닌 요구에 assert를 사용하지 않는 가장 큰 장점은 독자를 혼동하지 않는 것입니다. 코드를 비활성화하지 않으려면 해당 코드를 나타내는 관용구를 사용하지 마십시오. if (DEBUG)디버깅 코드 이외의 것을 제어 하는 데 사용 하는 것만 큼 ​​나쁩니다 . 미세 최적화는 귀하의 경우 아무 의미가 없습니다. 그러나 관용구가 필요하지 않기 때문에이 관용구를 파괴해서는 안됩니다.
candied_orange

나는 내 의도를 충분히 명확하게하지 않았다고 생각한다. 나는 특정 구현에 대한 assert것이 아니라 주장의 개념에 대해 이야기하고 있습니다. assert독자 를 오용 하거나 혼동 하고 싶지 않습니다 . 나는 그것이 왜 이런 식으로 처음인지 물었다. 추가가없는 이유는 무엇 release_assert입니까? 필요가 없습니까? 출시시 주장이 무효화되는 이유는 무엇입니까?
아무도

2
You're asking for a good abstraction.확실하지 않습니다. 나는 주로 회복이없고 결코 일어나지 않아야하는 문제들을 다루고 싶다. 이것을 함께 가져 Because production code needs to [...] not format the hard drive [...]가면 불변이 깨지는 경우 언제든지 UB를 통해 릴리스 할 것을 주장합니다.
아무도

1
@ 아무도 "복구가없는 문제"는 예외를 던지고 예외를 잡아서 처리 할 수 ​​없습니다. 예외 메시지 텍스트에서는 절대로 발생하지 않아야합니다.
candied_orange

4

어설 션은 방어 프로그래밍 기술 이 아니라 디버깅 도구 입니다. 모든 상황에서 유효성 검사를 수행하려면 조건부를 작성하여 유효성 검사를 수행하거나 고유 한 매크로를 만들어 상용구를 줄이십시오.


4

assert주석과 같은 문서 형식입니다. 주석과 마찬가지로 일반적으로 고객에게 제공하지 않으며 릴리스 코드에 속하지 않습니다.

그러나 주석의 문제점은 주석이 구식이 될 수 있지만 여전히 남아 있다는 것입니다. 이것이 어설 션이 좋은 이유입니다. 디버그 모드에서 확인됩니다. 어설 션이 더 이상 사용되지 않으면 신속하게 발견하고 어설 션을 수정하는 방법을 계속 알 수 있습니다. 3 년 전에 구식이 된 의견? 누구나 추측합니다.


1
따라서 어떤 문제가 발생하기 전에 실패한 불변에 대한 중단은 유효한 유스 케이스가 아닙니까?
아무도

3

"어설 션"을 끄지 않으려면 비슷한 효과가있는 간단한 함수를 작성하십시오.

void fail_if(bool b) {if(!b) std::abort();}

즉, assert당신은 시험을위한 이렇게 그들에게 제공되는 제품에 멀리 가고 싶어. 해당 테스트가 프로그램의 정의 된 동작의 일부 assert가되도록하려면 잘못된 도구입니다.


1
나는 이것을 잘 알고 있습니다. 문제는 기본값이 왜 그런지에 대한 선을 따라 더 있습니다.
아무도

3

주장이 무엇을해야하는지 논쟁하는 것은 의미가 없습니다. 다른 것을 원한다면 자신의 기능을 작성하십시오. 예를 들어 디버거에서 멈추거나 아무것도하지 않는 Assert가 있으며 앱을 중단시키는 AssertFatal이 있고 Asserted 및 AssertionFailed라는 bool 함수가있어 결과를 주장하고 반환하므로 상황을 주장하고 처리 할 수 ​​있습니다.

예기치 않은 문제가 발생하면 개발자와 사용자가 처리 할 수있는 가장 좋은 방법을 결정해야합니다.


주장이 무엇을해야하는지에 대한 논쟁은 저의 의도가 아닙니다. 이 질문에 대한 나의 동기는 내가 직접 작성하려고하고 유스 케이스, 기대치 및 함정에 대한 정보를 수집하려고하기 때문에 릴리스 빌드에 포함되지 않은 주장을 찾는 것이 었습니다.
아무도

흠, verify(cond)결과를 주장하고 반환하는 일반적인 방법이 아닐까요?
중복 제거기

1
나는 C가 아닌 Ruby로 코딩하고 있지만 백 트레이스를 인쇄하여 프로그램을 중지하는 것이 방어 적 프로그래밍 기술로 잘 작동하기 때문에 위의 답변 대부분에 동의하지 않습니다. 최대 주석 크기 문자로 아래에 다른 답변을 썼습니다.
Nakilon

2

다른 사람들이 지적했듯이 assert결코 일어나지 않아야 할 프로그래머 실수에 대한 마지막 방어 요새입니다. 그것들은 당신이 발송할 때까지 좌우로 실패하지 않아야하는 위생 검사입니다.

또한 개발자가 유용하다고 생각하는 이유 (미학, 성능, 원하는 것)에 관계없이 안정적인 릴리스 빌드에서 생략 되도록 설계되었습니다 . 디버그 빌드와 릴리스 빌드를 구분하는 것의 일부이며, 릴리스 빌드에는 그러한 주장이 없습니다. 따라서 전 처리기 정의가 정의되어 있고 정의 되지 않은 릴리스 빌드를 시도 하는 유사한 "어설 션이있는 릴리스 빌드" 를 릴리스하려는 경우 디자인의 하위 버전 이 있습니다 . 더 이상 릴리스 빌드가 아닙니다._DEBUGNDEBUG

디자인은 표준 라이브러리까지 확장됩니다. 수없이 많은 벡터를 구현하는 std::vector::operator[]것 중 가장 기본적인 예로써 assert, 벡터를 경계 밖으로 검사하지 않도록하기 위해 온 전성 검사를 수행합니다. 그리고 릴리스 빌드에서 이러한 검사를 활성화하면 표준 라이브러리가 훨씬 더 성능이 떨어지기 시작합니다. 의 벤치 마크 vector사용operator[]평범한 오래된 동적 배열에 대해 포함 된 주장이있는 채우기 ctor는 종종 이러한 검사를 비활성화 할 때까지 동적 배열이 상당히 빠르다는 것을 보여 주므로, 사소한 방식과는 거리가 멀지 만 성능에 영향을주는 경우가 많습니다. 여기에서 널 포인터 검사와 범위를 벗어난 검사는 그러한 검사가 스마트 포인터를 역 참조하거나 배열에 액세스하는 것처럼 코드 앞의 중요한 루프의 모든 프레임에 수백만 번 적용되는 경우 실제로 큰 비용이 될 수 있습니다.

따라서 주요 영역에서 이러한 온 전성 검사를 수행하는 릴리스 빌드를 원할 경우 작업에 대해 다른 도구와 릴리스 빌드에서 생략되지 않은 도구를 원할 것입니다. 내가 개인적으로 찾은 가장 유용한 것은 로깅입니다. 이 경우 사용자가 버그를보고하면 로그를 첨부하면 상황이 훨씬 쉬워지고 로그의 마지막 줄은 버그가 발생한 위치와 그 원인에 대한 큰 실마리를줍니다. 그런 다음 디버그 빌드에서 단계를 재현 할 때 마찬가지로 어설 션 오류가 발생하고 어설 션 오류로 인해 내 시간을 능률화 할 수있는 큰 단서가 생깁니다. 그러나 로깅은 상대적으로 비용이 많이 들기 때문에 일반적인 데이터 구조의 범위를 벗어나 배열에 액세스하지 않도록하는 것과 같이 매우 낮은 수준의 온 전성 검사를 적용하는 데 사용하지 않습니다.

그러나 마지막으로, 당신과 다소 동의하면, 알파 테스트 중에 디버그 빌드와 유사한 것을 테스터에게 실제로 전달하려는 합리적인 사례를 볼 수 있습니다 (예 : NDA에 서명 한 작은 알파 테스터 그룹) . 거기에서 테스터에게 소프트웨어를 실행하는 동안 실행할 수있는 테스트 및 더 자세한 출력과 같은 일부 디버깅 / 개발 기능과 함께 디버깅 정보가 첨부 된 정식 릴리스 빌드 이외의 것을 테스터에게 전달하면 알파 테스트가 간소화 될 수 있습니다. 나는 알파를 위해 그런 일을하는 몇몇 큰 게임 회사를 본 적이있다. 그러나 이것은 테스터에게 릴리스 빌드 이외의 것을 실제로 제공하려는 알파 또는 내부 테스트와 같은 것입니다. 실제로 릴리스 빌드를 제공하려는 경우 정의에 따라_DEBUG "debug"와 "release"빌드의 차이점을 정말로 혼동하는 정의 된 것입니다.

출시 전에이 코드를 제거해야하는 이유는 무엇입니까? 검사는 성능 저하가 많지 않고 실패하면 더 직접적인 오류 메시지를 선호하는 문제가 있습니다.

위에서 지적한 바와 같이, 점검이 반드시 성능 관점에서 사소한 것은 아니다. 많은 사람들이 사소한 것 같지만, 표준 lib조차도 그것을 사용하고 std::vector있으며, 최적화 된 릴리스 빌드로 간주되는 것에서 임의 액세스 통과의 시간이 4 배나 길 경우 많은 사람들에게 허용 할 수없는 방식으로 성능에 영향을 줄 수 있습니다 경계 검사로 인해 절대 실패하지 않아야합니다.

이전 팀에서는 실제로 행렬과 벡터 라이브러리가 디버그 빌드를 더 빠르게 실행하기 위해 특정 중요 경로에서 일부 어설트를 제외시켜야했습니다. 어설트는 수학 연산이 진행되는 시점까지 수학 연산 속도가 느려졌 기 때문입니다. 관심있는 코드를 추적하기 전에 15 분 정도 기다려야합니다. 제 동료들은 실제로asserts그들은 그렇게하는 것만으로도 엄청난 차이가 생겼다는 사실을 알게 되었기 때문입니다. 대신 우리는 중요한 디버그 경로를 피하도록 만들었습니다. 이러한 중요한 경로가 경계 검사를 거치지 않고 벡터 / 매트릭스 데이터를 직접 사용하게하면 전체 작업을 수행하는 데 필요한 시간 (벡터 / 매트릭스 수학 이상 포함)이 몇 분에서 몇 초로 단축되었습니다. 따라서 극단적 인 경우이지만 확실히 성능 주장에서 무시할 수있는 것은 아니며 확실하지도 않습니다.

그러나 그것은 단지 asserts설계된 방식 입니다. 그들이 전반적으로 그렇게 큰 성능 영향을 미치지 않았다면 디버그 빌드 기능 이상으로 설계되었거나 vector::at릴리스 빌드에서도 경계 검사를 포함하고 범위를 벗어난 것을 사용 하는 경우 선호 할 수 있습니다 액세스 (예 : 아직 성능이 크게 저하됨). 그러나 현재 필자의 경우에 성능에 큰 영향을 미치면 NDEBUG정의 할 때 생략되는 디버그 빌드 전용 기능으로 디자인이 훨씬 유용하다는 것을 알았습니다 . 적어도 내가 작업 한 경우 릴리스 빌드가 실제로 실패하지 않아야하는 위생 검사를 제외시키는 것은 큰 차이를 만듭니다.

vector::at vs. vector::operator[]

이 두 가지 방법의 차이점은 예외뿐만 아니라 대안의 핵심이라고 생각합니다. 범위를 벗어난 벡터에 액세스하려고 할 때 범위를 벗어난 액세스가 쉽게 재현 할 수있는 오류를 유발하는지 확인하기위한 vector::operator[]구현 assert. 그러나 라이브러리 구현자는 최적화 된 릴리스 빌드에서 비용이 들지 않는다는 가정하에이를 수행합니다.

한편 vector::at항상 경계가 체크 아웃을 수행하고 릴리스 빌드도에 던지는 제공하지만, 나는 종종 훨씬 더 코드를 사용하여 참조 점으로 IT 성능이 저하가됩니다 vector::operator[]보다가 vector::at. 많은 C ++ 디자인은 "사용 / 필요한 것에 대한 비용 지불"이라는 아이디어를 반영하며, 많은 사람들이 선호 operator[]하는 경우가 많으며 , 릴리스 빌드의 경계 검사를 방해하지 않는 경우도 있습니다. 최적화 된 릴리스 빌드에서 경계 검사가 필요하지 않습니다. 릴리스 빌드에서 어설 션이 활성화 된 경우이 두 가지의 성능은 동일하며 벡터 사용은 항상 동적 배열보다 느려집니다. 따라서 어설 션의 디자인 및 이점 중 상당 부분은 릴리스 빌드에서 자유 로워진다는 아이디어를 기반으로합니다.

release_assert

이것은 이러한 의도를 발견 한 후에 흥미 롭습니다. 당연히 모든 사람의 사용 사례는 다를 수 있지만release_assert 확인을 수행하고 릴리스 빌드에서도 라인 번호와 오류 메시지를 표시하는 소프트웨어에 충돌을 합니다.

예외가 발생했을 때처럼 소프트웨어가 정상적으로 복구되기를 원하지 않는 경우에는 모호한 경우가 있습니다. 이러한 경우 릴리스에서도 충돌이 발생하여 소프트웨어가 절대 발생하지 않아야 할 무언가를 발견했을 때 사용자에게 줄 번호를 줄 수 있기를 원합니다. 여전히 외부 입력 오류가 아닌 프로그래머 오류에 대한 위생 검사 영역에서 예외는 있지만 출시 비용에 대해 걱정하지 않고 충분히 저렴합니다.

실제로 줄 번호와 오류 메시지 가 발생하여 예외를 정상적으로 복구하는 것 보다 오류 가 발생하여 릴리스에 보관하기에 충분히 저렴한 경우가 있습니다. 또한 기존 예외에서 복구하려고 할 때 발생한 오류와 같이 예외에서 복구 할 수없는 경우가 있습니다. 필자 release_assert(!"This should never, ever happen! The software failed to fail!");는 처음에는 예외적 인 경로 내에서 검사가 수행되고 정상적인 실행 경로에서 비용이 들지 않기 때문에 먼지가 저렴하고 자연스럽게 완벽하게 적합하다는 것을 알았 습니다.


제 3 자 코드에서 어설 션을 활성화하지 않으려는 의도였습니다. 설명을 수정하십시오. 내 의견의 인용문은 내 질문의 맥락을 생략합니다. Additionally, the performance argument for me only counts when it is a measurable problem.따라서 아이디어는 릴리스에서 어설 션을 취할 때를 사례별로 결정하는 것입니다.
아무도

마지막 주석의 문제점 중 하나는 표준 라이브러리가 매크로를 사용할 때 사용 assert하는 것과 동일한 _DEBUG/NDEBUG전 처리기 정의 에 의존하는 것을 사용한다는 것 assert입니다. 따라서 예를 들어 표준 lib를 사용한다고 가정 할 때 표준 lib에 대해 코드를 활성화하지 않고 단 하나의 코드에 대해서만 어설 션을 선택적으로 활성화 할 수있는 방법이 없습니다.

STL 반복자 검사가있어 어설 션 중 일부만 비활성화 할 수 있지만 별도로 비활성화 할 수 있습니다.

기본적으로 세분화되지 않고 거친 도구이며 항상 릴리스에서 비활성화하려는 디자인 의도를 가지고 있으므로 팀 동료는 릴리스 성능에 영향을 미치지 않을 것이라는 가정과 비교하여 중요한 영역에서 도구를 사용할 수 있습니다. 표준 라이브러리는 다음을 사용합니다. 중요한 영역에서 다른 타사 라이브러리는 그 방식으로 사용합니다. 무언가를 원할 때 다른 코드가 아닌 더 구체적으로 하나의 코드를 비활성화 / 활성화 할 수 있습니다 assert.

vector::operator[]vector::at주장이 릴리스 빌드 및 사용에 아무 소용이 없을 것 활성화 된 경우, 예를 들어, 실질적으로 동일한 성능을 가질 것 operator[]어쨌든 확인 경계를하고있을 것 때문에 성능의 관점에서 더 이상.

2

C / C ++가 아닌 Ruby로 코딩하고 있으므로 어설 션과 예외의 차이점에 대해서는 이야기하지 않지만 런타임을 중지 시키는 것으로서 이야기하고 싶습니다 . 백 트레이스를 인쇄하여 프로그램을 중지하면 방어 프로그래밍 기술로 잘 작동하기 때문에 위의 대부분의 답변에 동의하지 않습니다 .
어설 션 루틴 (구문 적으로 작성되는 방법과 "어설 션"이라는 단어가 사용되거나 프로그래밍 언어 또는 dsl에 존재하는지 여부에 상관없이)을 호출 할 수있는 방법이있는 경우, 일부 작업을 수행하고 제품을 수행해야 함을 의미합니다. 즉시 "릴리스 된 즉시 사용 가능"에서 "패치 필요"로 되돌아갑니다. 이제 실제 예외 처리에 다시 쓰거나 잘못된 데이터가 나타나는 버그를 수정하십시오.

Assert는 여러분이 함께 살고 자주 전화해야하는 것이 아니라는 것을 의미합니다. 다시 신호가 발생하지 않도록 smth를 수행해야한다는 것을 나타내는 정지 신호입니다. 그리고 "릴리스 빌드에는 어떤 주장도 없어야한다"라는 말은 "릴리스 빌드에는 버그가 없어야한다"라고 말하는 것과 같습니다. 친구, 거의 불가능합니다.
또는 "최종 사용자가 수행 한 단위 테스트 실패"에 대해 생각하십시오. 사용자가 프로그램으로 할 일을 모두 예측할 수는 없지만 smth가 너무 심각하면 중지해야합니다. 빌드 파이프 라인을 만드는 방법과 비슷합니다. 프로세스를 중단하고 게시하지 마십시오. ? 어설 션은 사용자가 도움말을 중지,보고 및 대기하도록합니다.

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