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_assert выражений. Каждое контрактное утверждение имеет предикат  , который является выражением типа bool .

Оценка контрактных утверждений

Оценка утверждения контракта использует одну из следующих семантик оценки:

Семантика оценки Является проверяющей семантикой Является завершающей семантикой
ignore
observe Да
enforce Да Да
quick-enforce Да Да

Реализация определяет, какая семантика оценки используется для любого заданного вычисления утверждения контракта. Семантика оценки может различаться для разных вычислений одного и того же утверждения контракта, включая вычисления во время константной оценки.

Если используется семантика "ignore", оценка утверждения контракта не оказывает никакого эффекта.

Если используется проверяющая семантика, вычисление E утверждения контракта определяет значение предиката. Не указано, вычисляется ли предикат. Если выполняется любое из следующих условий, происходит нарушение контракта :

Существует наблюдаемая точка контроля CP , которая происходит до E , такая что любая другая операция OP , которая происходит до A , также происходит до CP .

int num = 0;
void f() pre((num++, false));
f(); // Инкремент "num" может не произойти, даже если используется проверяющая семантика

Обработка нарушений контракта

Если нарушение контракта происходит в контексте, который является явно константно-вычисляемым:

  • Если семантика вычисления — «наблюдение», создается диагностическое сообщение.
  • Если семантика вычисления является завершающей семантикой, программа считается некорректной.

Если нарушение контракта происходит в контексте, который не является явно константно-вычисляемым:

  • Если семантика оценки — «quick-enforce», программа завершается по контракту.
  • Если семантика оценки — «enforce» или «observe», вызывается обработчик нарушения контракта со ссылкой на lvalue объекта obj типа const std :: contracts :: contract_violation , содержащего информацию о нарушении контракта.
    • Память для obj выделяется неопределённым образом, но глобальная функция выделения памяти не будет вызвана.
    • Время жизни obj сохраняется на протяжении всего вызова обработчика нарушения контракта.

Программы с завершенным контрактом

Когда программа contract-terminated  , определяется реализацией (в зависимости от контекста), будет ли

Обработчик нарушения контракта

Обработчик нарушения контракта программы — это функция с именем :: handle_contract_violation :

void handle_contract_violation ( std :: contracts :: contract_violation ) ;
(начиная с C++26)
(опционально noexcept)

Определение обработчика нарушения контракта, называемого обработчиком нарушения контракта по умолчанию  , предоставляется реализацией (вместо заголовочного файла стандартной библиотеки).

Является ли обработчик нарушения контракта заменяемым — определяется реализацией. Если обработчик нарушения контракта не является заменяемым, объявление заменяющей функции для обработчика нарушения контракта является некорректным, диагностика не требуется.

Когда обработчик нарушения контракта возвращается нормально:

  • Если семантика оценки — «observe», поток управления продолжается нормально после точки оценки утверждения контракта.
  • Если семантика оценки — «enforce», программа завершается по контракту.

Существует наблюдаемая точка контроля CP , которая возникает после нормального возврата обработчика нарушения контракта, так что любая другая операция OP , происходящая после возврата обработчика нарушения контракта, также происходит после CP .

Обработка исключений из утверждений

Если нарушение контракта произошло из-за того, что вычисление предиката завершилось с исключением и семантика вычисления имеет значение "observe" или "enforce", обработчик нарушения контракта вызывается из активного неявного handler для этого исключения.

Когда обработчик нарушения контракта возвращается нормально:

  • Если семантика оценки — «observe», неявный обработчик больше не считается активным.
  • Если семантика оценки — «enforce», неявный обработчик остается активным при завершении контракта.

Текущее исключение может быть проверено или повторно выброшено в обработчике нарушения контракта с помощью std::current_exception() .

Выполнять последовательно

Для последовательной оценки списка R контрактных утверждений:

1) Построить список контрактных утверждений S , удовлетворяющий всем следующим условиям:
  • Все элементы R содержатся в S .
  • Каждый элемент R может повторяться в S определённое реализацией количество раз.
  • Если контрактное утверждение A предшествует другому контрактному утверждению B в R , то первое вхождение A предшествует первому вхождению B в S .
2) Вычислите каждый элемент S таким образом, что если контрактное утверждение A предшествует контрактному утверждению B в S , тогда вычисление A упорядочено перед вычислением B .
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       (первые вхождения не могут менять порядок)
}

Примечания

Диапазон и гибкость доступных вариантов семантики вычислений зависят от реализации и не обязательно должны допускать все четыре варианта семантики вычислений как возможные.

Различные семантики оценки, выбранные для одного и того же контрактного утверждения в разных единицах трансляции, могут привести к нарушению правила одного определения когда контрактное утверждение имеет побочные эффекты, изменяющие значение, производимое константным выражением:

constexpr int f(int i)
{
    contract_assert((++const_cast<int&>(i), true));
    return i;
}
inline void g()
{
    int a[f(1)]; // размер зависит от семантики вычисления contract_assert выше
}

Если значение, которое получится в результате вычисления предиката, равно true , нарушение контракта не происходит, и управление продолжается нормально после точки вычисления утверждения контракта.

Если вычисление предиката завершается посредством нелокальных переходов или завершения программы, нарушение контракта также не происходит.

Рекомендуется стандартом C++, что обработчик нарушений контракта по умолчанию должен выдавать диагностический вывод, который соответствующим образом форматирует наиболее релевантное содержимое аргумента (с ограничением частоты для потенциально повторяющихся нарушений наблюдаемых утверждений контракта), и затем возвращаться нормально.

Макрос тестирования возможностей Значение Стандарт Возможность
__cpp_contracts 202502L (C++26) Контракты

Ключевые слова

contract_assert , pre , post

Статус поддержки

Функция C++26

Документ(ы)

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


Контракты ( FTM ) * P2900R14

Смотрите также

contract_assert statement (C++26) проверяет внутреннее условие во время выполнения
function contract specifiers (C++26) определяет предусловия ( pre ) и постусловия ( post )