Contract assertions (since C++26)
Les assertions contractuelles permettent au programmeur de spécifier des propriétés de l'état du programme qui sont censées être vérifiées à certains points durant l'exécution.
Table des matières |
Explication
Assertions contractuelles
sont introduites par les
spécificateurs de contrat de fonction
et les instructions
contract_assert
. Chaque assertion contractuelle possède un
prédicat
, qui est une expression de type
bool
.
Évaluation des assertions de contrat
L'évaluation d'une assertion contractuelle utilise l'une des sémantiques d'évaluation suivantes :
| Sémantique d'évaluation | Est une sémantique de vérification | Est une sémantique de terminaison |
|---|---|---|
| ignorer | ||
| observer | Oui | |
| appliquer | Oui | Oui |
| appliquer-rapide | Oui | Oui |
Il est défini par l'implémentation quelle sémantique d'évaluation est utilisée pour toute évaluation donnée d'une assertion de contrat. Les sémantiques d'évaluation peuvent différer pour différentes évaluations de la même assertion de contrat, y compris les évaluations durant l'évaluation constante.
Si la sémantique « ignore » est utilisée, l'évaluation d'une assertion de contrat n'a aucun effet.
Si une sémantique de vérification est utilisée, l'évaluation
E
d'une assertion contractuelle détermine la valeur du prédicat. Il n'est pas spécifié si le prédicat est évalué. Si l'une des conditions suivantes est satisfaite, une
violation de contrat
se produit :
- La valeur qui résulterait de l'évaluation du prédicat est false .
- L'évaluation du prédicat se termine via une exception.
- L'évaluation du prédicat est effectuée dans un contexte qui est manifestement constant-évalué et le prédicat n'est pas une expression constante de base .
Il existe un
point de contrôle observable
CP
qui se produit avant
E
tel que
toute autre opération
OP
qui se produit avant
A
se produit également avant
CP
.
int num = 0; void f() pre((num++, false)); f(); // L'incrémentation de « num » pourrait ne pas se produire, même si une sémantique de vérification est utilisée
Gestion des violations de contrat
Si une violation de contrat se produit dans un contexte manifestement évalué de manière constante :
- Si la sémantique d'évaluation est « observe », un diagnostic est produit.
- Si la sémantique d'évaluation est une sémantique de terminaison, le programme est mal formé.
Si une violation de contrat survient dans un contexte qui n'est pas manifestement évalué de manière constante :
- Si la sémantique d'évaluation est « quick-enforce », le programme est terminé par contrat.
-
Si la sémantique d'évaluation est « enforce » ou « observe », le gestionnaire de violation de contrat est invoqué avec une lvalue se référant à un objet
obj
de type
const
std
::
contracts
::
contract_violation
contenant des informations sur la violation du contrat.
- Le stockage pour obj est alloué de manière non spécifiée, mais aucune fonction d'allocation globale ne sera invoquée.
- La durée de vie de obj persiste pendant la durée de l'invocation du gestionnaire de violation de contrat.
Programmes résiliés par contrat
Lorsque le programme est contract-terminated , il est défini par l'implémentation (selon le contexte) si
- std::terminate est appelé,
- std::abort est appelé, ou
- l'exécution est terminée (aucune étape d'exécution supplémentaire ne se produit).
Gestionnaire de violation de contrat
Le gestionnaire de violation de contrat d'un programme est une fonction nommée :: handle_contract_violation :
|
void
handle_contract_violation
(
std
::
contracts
::
contract_violation
)
;
|
(depuis C++26)
(optionnellement noexcept) |
|
Une définition du gestionnaire de violation de contrat, appelé le gestionnaire de violation de contrat par défaut , est fournie par l'implémentation (au lieu d'un en-tête de bibliothèque standard).
Il est défini par l'implémentation si le gestionnaire de violation de contrat est remplaçable . Si le gestionnaire de violation de contrat n'est pas remplaçable, une déclaration d'une fonction de remplacement pour le gestionnaire de violation de contrat est mal formée, aucun diagnostic requis.
Lorsque le gestionnaire de violation de contrat retourne normalement :
- Si la sémantique d'évaluation est « observe », le flux de contrôle continue normalement après le point d'évaluation de l'assertion de contrat.
- Si la sémantique d'évaluation est « enforce », le programme est terminé par contrat.
Il existe un
point de contrôle observable
CP
qui se produit après que le gestionnaire de violation de contrat retourne normalement, de sorte que toute autre opération
OP
qui se produit après que le gestionnaire de violation de contrat retourne se produit également après
CP
.
Gestion des exceptions provenant des assertions
Si la violation du contrat s'est produite parce que l'évaluation du prédicat s'est terminée via une exception et que la sémantique d'évaluation est « observe » ou « enforce », le gestionnaire de violation de contrat est invoqué depuis un gestionnaire implicite actif pour cette exception.
Lorsque le gestionnaire de violation de contrat retourne normalement :
- Si la sémantique d'évaluation est « observe », le gestionnaire implicite n'est plus considéré comme actif.
- Si la sémantique d'évaluation est « enforce », le gestionnaire implicite reste actif lors de la terminaison du contrat.
L'exception actuelle peut être inspectée ou relancée dans le gestionnaire de violation de contrat en utilisant std::current_exception() .
Évaluer en séquence
Pour
évaluer en séquence
une liste
R
d'assertions de contrat :
S
telle que toutes les conditions suivantes soient satisfaites :
-
Tous les éléments de
Rsont dansS. -
Chaque élément de
Rpeut être répété un nombre de fois défini par l'implémentation dansS. -
Si une assertion de contrat
Aprécède une autre assertion de contratBdansR, alors la première occurrence deAprécède la première occurrence deBdansS.
S
de telle sorte que, si une assertion de contrat
A
précède une assertion de contrat
B
dans
S
, alors l'évaluation de
A
est
séquencée avant
l'évaluation de
B
.
void f(int i) { contract_assert(i > 0); // #1 contract_assert(i < 10); // #2 // séquence d'évaluations valide : #1 #2 (pas de répétition) // séquence d'évaluations valide : #1 #1 #2 #2 (répétition en séquence) // séquence d'évaluations valide : #1 #2 #1 #2 (répétition alternative) // séquence d'évaluations valide : #1 #2 #2 #1 (les secondes occurrences peuvent changer d'ordre) // séquence d'évaluations invalide : #2 #1 (les premières occurrences ne peuvent pas changer d'ordre) }
Notes
La portée et la flexibilité des choix disponibles de sémantiques d'évaluation dépendent de l'implémentation, et ne doivent pas nécessairement permettre les quatre sémantiques d'évaluation comme possibilités.
Le choix de sémantiques d'évaluation différentes pour la même assertion de contrat dans différentes unités de traduction peut entraîner des violations de la règle de définition unique lorsqu'une assertion de contrat a des effets secondaires qui modifient la valeur produite par une expression constante :
constexpr int f(int i) { contract_assert((++const_cast<int&>(i), true)); return i; } inline void g() { int a[f(1)]; // taille dépendante de la sémantique d'évaluation de contract_assert ci-dessus }
Si la valeur qui résulterait de l'évaluation du prédicat est true , aucune violation de contrat ne se produit et le flux de contrôle continue normalement après le point d'évaluation de l'assertion de contrat.
Si l'évaluation du prédicat se termine par des sauts non locaux ou en terminant le programme, aucune violation de contrat ne se produit non plus.
Il est recommandé par la norme C++ que le gestionnaire par défaut de violation de contrat devrait produire une sortie de diagnostic qui formate de manière appropriée les contenus les plus pertinents de l'argument (avec limitation de débit pour les violations potentiellement répétées des assertions de contrat observées), puis retourne normalement.
| Macro de test de fonctionnalité | Valeur | Std | Fonctionnalité |
|---|---|---|---|
__cpp_contracts
|
202502L
|
(C++26) | Contrats |
Mots-clés
contract_assert , pre , post
État de la prise en charge
|
Fonctionnalité C++26
|
Document(s)
|
GCC
|
Clang
|
MSVC
|
Apple Clang
|
EDG eccp
|
Intel C++
|
Nvidia HPC C++ (ex PGI)*
|
Nvidia nvcc
|
Cray
|
|---|---|---|---|---|---|---|---|---|---|---|
| Contracts ( FTM ) * | P2900R14 |
Voir aussi
contract_assert
statement
(C++26)
|
vérifie une condition interne durant l'exécution |
| spécificateurs de contrat de fonction (C++26) | spécifie les préconditions ( pre ) et postconditions ( post ) |