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

Las aserciones de contrato permiten al programador especificar propiedades del estado del programa que se espera que se cumplan en ciertos puntos durante la ejecución.

Contenidos

Explicación

Aserciones de contrato son introducidas por especificadores de contrato de función y contract_assert . Cada aserción de contrato tiene un predicado  , que es una expresión de tipo bool .

Evaluación de aserciones de contrato

Una evaluación de una aserción de contrato utiliza una de las siguientes semánticas de evaluación:

Semántica de evaluación Es una semántica de verificación Es una semántica de terminación
ignorar
observar
hacer cumplir
hacer cumplir-rápido

Es definido por la implementación qué semántica de evaluación se utiliza para cualquier evaluación dada de una aserción de contrato. La semántica de evaluación puede diferir para diferentes evaluaciones de la misma aserción de contrato, incluyendo evaluaciones durante la evaluación constante.

Si se utiliza la semántica de "ignorar", la evaluación de una aserción de contrato no tiene efecto.

Si se utiliza una semántica de verificación, la evaluación E de una aserción de contrato determina el valor del predicado. No está especificado si el predicado es evaluado. Si se satisface alguna de las siguientes condiciones, ocurre una violación de contrato :

Existe un punto de observación CP que ocurre antes de E tal que cualquier otra operación OP que ocurre antes de A también ocurre antes de CP .

int num = 0;
void f() pre((num++, false));
f(); // El incremento de "num" podría no ocurrir, incluso si se utiliza una semántica de verificación

Manejo de violaciones de contrato

Si se produce una violación de contrato en un contexto que está manifiestamente evaluado como constante:

  • Si la semántica de evaluación es "observe", se produce un diagnóstico.
  • Si la semántica de evaluación es una semántica terminante, el programa está mal formado.

Si ocurre una violación de contrato en un contexto que no está manifiestamente evaluado como constante:

  • Si la semántica de evaluación es "quick-enforce", el programa es terminado por contrato.
  • Si la semántica de evaluación es "enforce" u "observe", se invoca el manejador de violación de contrato con un lvalue que hace referencia a un objeto obj de tipo const std :: contracts :: contract_violation que contiene información sobre la violación del contrato.
    • El almacenamiento para obj se asigna de manera no especificada, pero no se invocará ninguna función de asignación global .
    • El tiempo de vida de obj persiste durante la duración de la invocación del manejador de violación de contrato.

Programas terminados por contrato

Cuando el programa es contract-terminated  , está definido por la implementación (dependiendo del contexto) si

Manejador de violación de contrato

El manejador de violación de contrato de un programa es una función llamada :: handle_contract_violation :

void handle_contract_violation ( std :: contracts :: contract_violation ) ;
(desde C++26)
(opcionalmente noexcept)

Una definición del manejador de violación de contrato, llamado manejador de violación de contrato predeterminado  , es proporcionada por la implementación (en lugar de un encabezado de biblioteca estándar).

Es definido por la implementación si el manejador de violación de contrato es reemplazable . Si el manejador de violación de contrato no es reemplazable, una declaración de una función de reemplazo para el manejador de violación de contrato está mal formada, no se requiere diagnóstico.

Cuando el manejador de violación de contrato retorna normalmente:

  • Si la semántica de evaluación es "observe", el flujo de control continúa normalmente después del punto de evaluación de la aserción del contrato.
  • Si la semántica de evaluación es "enforce", el programa termina por contrato.

Existe un punto de verificación observable CP que ocurre después de que el manejador de violación de contrato retorna normalmente, de modo que cualquier otra operación OP que ocurra después de que el manejador de violación de contrato retorne también ocurre después de CP .

Manejo de excepciones desde aserciones

Si la violación del contrato ocurrió porque la evaluación del predicado salió mediante una excepción y la semántica de evaluación es "observe" o "enforce", el manejador de violación de contrato se invoca desde dentro de un handler implícito activo para esa excepción.

Cuando el manejador de violación de contrato retorna normalmente:

  • Si la semántica de evaluación es "observe", el manejador implícito ya no se considera activo.
  • Si la semántica de evaluación es "enforce", el manejador implícito permanece activo cuando ocurre la terminación del contrato.

La excepción actual puede ser inspeccionada o relanzada dentro del manejador de violación de contrato usando std::current_exception() .

Evaluar en secuencia

Para evaluar en secuencia una lista R de aserciones de contrato:

1) Construya una lista de aserciones de contrato S tal que se cumplan todas las siguientes condiciones:
  • Todos los elementos de R están en S .
  • Cada elemento de R puede repetirse un número definido por la implementación dentro de S .
  • Si una aserción de contrato A precede a otra aserción de contrato B en R , entonces la primera ocurrencia de A precede a la primera ocurrencia de B en S .
2) Evalúe cada elemento de S de tal manera que, si una aserción de contrato A precede a una aserción de contrato B en S , entonces la evaluación de A está secuenciada antes que la evaluación de B .
void f(int i)
{
    contract_assert(i > 0);  // #1
    contract_assert(i < 10); // #2
    // secuencia válida de evaluaciones:   #1 #2       (sin repetición)
    // secuencia válida de evaluaciones:   #1 #1 #2 #2 (repetición en secuencia)
    // secuencia válida de evaluaciones:   #1 #2 #1 #2 (repetición alternada)
    // secuencia válida de evaluaciones:   #1 #2 #2 #1 (las segundas ocurrencias pueden cambiar de orden)
    // secuencia inválida de evaluaciones: #2 #1       (las primeras ocurrencias no pueden cambiar)
}

Notas

El rango y flexibilidad de las opciones disponibles de semánticas de evaluación depende de la implementación, y no necesita permitir las cuatro semánticas de evaluación como posibilidades.

Diferentes semánticas de evaluación elegidas para la misma aserción de contrato en distintas unidades de traducción pueden resultar en violaciones de la regla de una definición cuando una aserción de contrato tiene efectos secundarios que alteran el valor producido por una expresión constante:

constexpr int f(int i)
{
    contract_assert((++const_cast<int&>(i), true));
    return i;
}
inline void g()
{
    int a[f(1)]; // tamaño depende de la semántica de evaluación de contract_assert anterior
}

Si el valor que resultaría de evaluar el predicado es true , no ocurre ninguna violación de contrato y el flujo de control continúa normalmente después del punto de evaluación de la aserción del contrato.

Si la evaluación del predicado finaliza mediante saltos no locales o terminando el programa, tampoco ocurre ninguna violación de contrato.

Se recomienda por el estándar de C++ que el manejador predeterminado de violación de contrato debe producir una salida de diagnóstico que formatee adecuadamente los contenidos más relevantes del argumento (con limitación de tasa para violaciones potencialmente repetidas de aserciones de contrato observadas), y luego retorne normalmente.

Macro de prueba de características Valor Std Característica
__cpp_contracts 202502L (C++26) Contracts

Palabras clave

contract_assert , pre , post

Estado de compatibilidad

Característica de C++26

Documento(s)

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


Contracts ( FTM ) * P2900R14

Véase también

contract_assert sentencia (C++26) verifica una condición interna durante la ejecución
especificadores de contrato de función (C++26) especifica precondiciones ( pre ) y postcondiciones ( post )