Namespaces
Variants

Contract assertions (since C++26)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

계약 어서션(contract assertions)을 사용하면 프로그래머는 프로그램 실행 중 특정 지점에서 유지될 것으로 예상되는 프로그램 상태의 속성을 명시할 수 있습니다.

목차

설명

계약 단언문 함수 계약 지정자 contract_assert 문으로 도입됩니다. 각 계약 단언문은 술어  를 가지며, 이는 bool 타입의 표현식입니다.

계약 어서션 평가

계약 어설션 평가는 다음 평가 의미론 중 하나를 사용합니다:

평가 의미론 검사 의미론 여부 종료 의미론 여부
무시
관찰
강제
신속 강제

계약 어설션의 주어진 평가에 대해 어떤 평가 의미론이 사용되는지는 구현에 따라 정의됩니다. 평가 의미론은 동일한 계약 어설션의 서로 다른 평가마다 다를 수 있으며, 상수 평가 중의 평가도 포함됩니다.

"ignore" 의미가 사용되면, 계약 어설션 평가는 아무런 효과를 가지지 않습니다.

검사 의미 체계가 사용되는 경우, 계약 어설션의 평가 E 는 술어의 값을 결정합니다. 술어가 평가되는지 여부는 명시되지 않습니다. 다음 조건 중 하나라도 충족되면 계약 위반 이 발생합니다:

E 이전에 발생하는 관찰 가능 체크포인트 CP 가 존재하여, A 이전에 발생하는 다른 모든 연산 OP CP 이전에 발생합니다.

int num = 0;
void f() pre((num++, false));
f(); // "num"의 증가가 발생하지 않을 수 있습니다. 심지어 검사 의미론이 사용되는 경우에도

계약 위반 처리

계약 위반이 명백하게 상수 평가되는 맥락에서 발생하는 경우:

  • 평가 의미(evaluation semantic)가 "observe"인 경우, 진단 정보가 생성됩니다.
  • 평가 의미(evaluation semantic)가 종료 의미(terminating semantic)인 경우, 프로그램은 형식에 맞지 않습니다(ill-formed).

계약 위반이 명백하게 상수 평가되지 않는 맥락에서 발생하는 경우:

  • 평가 의미론이 "quick-enforce"인 경우, 프로그램은 계약 종료됩니다.
  • 평가 의미론이 "enforce" 또는 "observe"인 경우, 계약 위반 핸들러가 계약 위반에 대한 정보를 포함하는 const std :: contracts :: contract_violation 타입의 객체 obj 를 참조하는 lvalue와 함께 호출됩니다.
    • obj 의 저장 공간은 지정되지 않은 방식으로 할당되지만, 전역 allocation function 은 호출되지 않습니다.
    • obj 의 수명은 계약 위반 핸들러 호출 기간 동안 지속됩니다.

계약 종료 프로그램

프로그램이 contract-terminated  될 때, 구현에 따라 (컨텍스트에 따라) 다음 여부가 결정됩니다

계약 위반 핸들러

프로그램의 계약 위반 처리기 :: handle_contract_violation 라는 이름의 함수입니다:

void handle_contract_violation ( std :: contracts :: contract_violation ) ;
(C++26부터)
(선택적으로 noexcept)

계약 위반 처리기의 정의, 즉 기본 계약 위반 처리기  는 구현에 의해 제공됩니다(표준 라이브러리 헤더 대신).

계약 위반 핸들러가 교체 가능한지 여부는 구현에 따라 정의됩니다. 계약 위반 핸들러가 교체 불가능한 경우, 계약 위반 핸들러에 대한 교체 함수 선언은 진단 없이 잘못된 형식입니다.

계약 위반 핸들러가 정상적으로 반환될 때:

  • 평가 의미가 "observe"인 경우, 계약 단언 평가 지점 이후로 제어 흐름이 정상적으로 계속됩니다.
  • 평가 의미가 "enforce"인 경우, 프로그램이 계약 종료됩니다.

계약 위반 핸들러가 정상적으로 반환된 후 발생하는 관찰 가능한 체크포인트 CP 가 존재하며, 계약 위반 핸들러가 반환된 후 발생하는 다른 모든 연산 OP CP 이후에 발생합니다.

단언문에서 발생하는 예외 처리

계약 위반이 술어 평가가 예외를 통해 종료되어 발생했고 평가 의미론이 "observe" 또는 "enforce"인 경우, 계약 위반 핸들러는 해당 예외에 대한 활성 암시적 핸들러 내부에서 호출됩니다.

계약 위반 핸들러가 정상적으로 반환될 때:

  • 평가 의미론이 "observe"인 경우, 암시적 핸들러는 더 이상 활성 상태로 간주되지 않습니다.
  • 평가 의미론이 "enforce"인 경우, 계약 종료가 발생할 때 암시적 핸들러는 계속 활성 상태를 유지합니다.

현재 예외는 계약 위반 핸들러 내에서 std::current_exception() 를 사용하여 검사하거나 다시 던질 수 있습니다.

순차적으로 평가

계약 단언(assertion) 목록 R 순차적으로 평가 하려면:

1) 계약 조건 어설션 목록 S 를 다음과 같은 모든 조건을 만족하도록 구성하시오:
  • R 의 모든 요소가 S 에 포함되어야 합니다.
  • R 의 각 요소는 구현에서 정의된 횟수만큼 S 내에서 반복될 수 있습니다.
  • 계약 조건 어설션 A R 에서 다른 계약 조건 어설션 B 보다 앞선 경우, S 에서 A 의 첫 번째 발생은 B 의 첫 번째 발생보다 앞서야 합니다.
2) S 의 각 요소를 다음과 같이 평가합니다: 만약 계약 어서션 A 가 계약 어서션 B 보다 S 에서 앞선다면, A 의 평가는 B 의 평가보다 sequenced before 됩니다.
void f(int i)
{
    contract_assert(i > 0);  // #1
    contract_assert(i < 10); // #2
    // 유효한 평가 순서:   #1 #2       (반복 없음)
    // 유효한 평가 순서:   #1 #1 #2 #2 (순차적으로 반복)
    // 유효한 평가 순서:   #1 #2 #1 #2 (교대로 반복)
    // 유효한 평가 순서:   #1 #2 #2 #1 (두 번째 발생은 순서 변경 가능)
    // 유효하지 않은 평가 순서: #2 #1       (첫 번째 발생은 순서 변경 불가)
}

참고 사항

평가 의미론의 사용 가능한 선택 범위와 유연성은 구현에 따라 다르며, 네 가지 평가 의미론 모두를 가능성으로 허용할 필요는 없습니다.

동일한 계약 조건 단언문에 대해 서로 다른 번역 단위에서 선택된 상이한 평가 의미론은 계약 조건 단언문이 상수 표현식에 의해 생성된 값을 변경하는 부수 효과를 가질 때 one-definition rule 위반을 초래할 수 있습니다:

constexpr int f(int i)
{
    contract_assert((++const_cast<int&>(i), true));
    return i;
}
inline void g()
{
    int a[f(1)]; // 위의 contract_assert 평가 의미론에 따라 크기가 결정됨
}

술어를 평가하여 얻게 될 값이 true 인 경우, 계약 위반이 발생하지 않으며 제어 흐름은 계약 단언 평가 지점 이후로 정상적으로 계속됩니다.

술어(predicate)의 평가가 비지역 점프(non-local jumps) 또는 프로그램 종료를 통해 종료되는 경우, 계약 위반(contract violation)도 발생하지 않습니다.

C++ 표준에서는 기본 계약 위반 핸들러가 인수의 가장 관련성 높은 내용을 적절히 형식화하여 진단 출력을 생성하고(관찰된 계약 어설션의 잠재적 반복 위반에 대해 속도 제한 적용), 그런 다음 정상적으로 반환하는 것을 권장합니다.

기능 테스트 매크로 표준 기능
__cpp_contracts 202502L (C++26) Contracts

키워드

contract_assert , pre , post

지원 상태

C++26 기능

문서

GCC
Clang
MSVC
Apple Clang
EDG eccp
Intel C++
Nvidia HPC C++ (ex PGI)*
Nvidia nvcc
Cray


Contracts ( FTM ) * P2900R14

참고 항목

contract_assert statement (C++26) 실행 중 내부 조건을 검증
function contract specifiers (C++26) 사전 조건( pre )과 사후 조건( post )을 명시