Contract assertions (since C++26)
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 | Sí | |
| hacer cumplir | Sí | Sí |
| hacer cumplir-rápido | Sí | Sí |
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
:
- El valor que resultaría de evaluar el predicado es false .
- La evaluación del predicado termina mediante una excepción.
- La evaluación del predicado se realiza en un contexto que está manifestly constant-evaluated y el predicado no es un core constant expression .
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
- std::terminate es llamado,
- std::abort es llamado, o
- la ejecución es terminada (no ocurren más pasos de ejecución ).
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:
S
tal que se cumplan todas las siguientes condiciones:
-
Todos los elementos de
Restán enS. -
Cada elemento de
Rpuede repetirse un número definido por la implementación dentro deS. -
Si una aserción de contrato
Aprecede a otra aserción de contratoBenR, entonces la primera ocurrencia deAprecede a la primera ocurrencia deBenS.
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 ) |