Contract assertions (since C++26)
Vertragsassertionen ermöglichen es dem Programmierer, Eigenschaften des Programmzustands anzugeben, die an bestimmten Punkten während der Ausführung erwartet werden.
Inhaltsverzeichnis |
Erklärung
Vertragsassertionen
werden durch
Funktionsvertragsspezifizierer
und
contract_assert
-Anweisungen eingeführt. Jede Vertragsassertion besitzt ein
Prädikat
, welches ein Ausdruck vom Typ
bool
ist.
Auswertung von Contract-Assertions
Eine Auswertung einer Vertragsassertion verwendet eine der folgenden Auswertungssemantiken:
| Auswertungssemantik | Ist eine prüfende Semantik | Ist eine terminierende Semantik |
|---|---|---|
| ignore | ||
| observe | Yes | |
| enforce | Yes | Yes |
| quick-enforce | Yes | Yes |
Es ist implementierungsdefiniert, welche Auswertungssemantik für eine bestimmte Auswertung einer Contract-Assertion verwendet wird. Die Auswertungssemantik kann sich für verschiedene Auswertungen derselben Contract-Assertion unterscheiden, einschließlich Auswertungen während der Konstantenauswertung.
Wenn die "ignore"-Semantik verwendet wird, hat die Auswertung einer Contract-Assertion keine Auswirkung.
Wenn eine prüfende Semantik verwendet wird, bestimmt die Auswertung
E
einer Vertragsassertion den Wert des Prädikats. Es ist nicht spezifiziert, ob das Prädikat ausgewertet wird. Wenn eine der folgenden Bedingungen erfüllt ist, tritt eine
Vertragsverletzung
auf:
- Der Wert, der sich aus der Auswertung des Prädikats ergeben würde, ist false .
- Die Auswertung des Prädikats wird über eine Exception beendet.
- Die Auswertung des Prädikats wird in einem Kontext durchgeführt, der offensichtlich konstant ausgewertet wird, und das Prädikat ist kein Core Constant Expression .
Es gibt einen
beobachtbaren Kontrollpunkt
CP
, der vor
E
stattfindet, sodass
jede andere Operation
OP
, die vor
A
stattfindet, ebenfalls vor
CP
stattfindet.
int num = 0; void f() pre((num++, false)); f(); // Die Inkrementierung von "num" könnte nicht erfolgen, selbst wenn eine prüfende Semantik verwendet wird
Behandlung von Vertragsverletzungen
Wenn ein Vertragsverstoß in einem Kontext auftritt, der offensichtlich konstant ausgewertet wird:
- Wenn die Evaluierungssemantik "observe" ist, wird eine Diagnose erzeugt.
- Wenn die Evaluierungssemantik eine terminierende Semantik ist, ist das Programm fehlerhaft.
Wenn ein Vertragsverstoß in einem Kontext auftritt, der nicht offensichtlich konstant ausgewertet wird:
- Wenn die Auswertungssemantik "quick-enforce" ist, wird das Programm durch Vertragsabbruch beendet.
-
Wenn die Auswertungssemantik "enforce" oder "observe" ist, wird der Vertragsverletzungs-Handler mit einem L-Wert aufgerufen, der sich auf ein Objekt
obj
vom Typ
const
std
::
contracts
::
contract_violation
bezieht, der Informationen über die Vertragsverletzung enthält.
- Der Speicher für obj wird auf nicht spezifizierte Weise allokiert, jedoch wird keine globale Allokationsfunktion aufgerufen.
- Die Lebensdauer von obj besteht für die Dauer des Aufrufs des Vertragsverletzungs-Handlers.
Vertragsbeendigte Programme
Wenn das Programm contract-terminated wird, ist implementierungsdefiniert (abhängig vom Kontext), ob
- std::terminate wird aufgerufen,
- std::abort wird aufgerufen, oder
- die Ausführung wird beendet (keine weiteren Ausführungsschritte erfolgen).
Contract-Verletzungs-Handler
Der Contract-Verletzungs-Handler eines Programms ist eine Funktion namens :: handle_contract_violation :
|
void
handle_contract_violation
(
std
::
contracts
::
contract_violation
)
;
|
(seit C++26)
(optional noexcept) |
|
Eine Definition des Vertragsverletzungs-Handlers, genannt der Standard-Vertragsverletzungs-Handler , wird durch die Implementierung bereitgestellt (anstatt durch eine Standardbibliothek-Header-Datei).
Es ist implementierungsdefiniert, ob der Vertragsverletzungs-Handler ersetzbar ist. Wenn der Vertragsverletzungs-Handler nicht ersetzbar ist, ist eine Deklaration einer Ersatzfunktion für den Vertragsverletzungs-Handler ill-formed, keine Diagnose erforderlich.
Wenn der Vertragsverletzungs-Handler normal zurückkehrt:
- Wenn die Auswertungssemantik "observe" ist, setzt der Kontrollfluss normal nach dem Auswertungspunkt der Vertragsassertion fort.
- Wenn die Auswertungssemantik "enforce" ist, wird das Programm vertragsbeendet.
Es gibt einen
beobachtbaren Kontrollpunkt
CP
, der stattfindet, nachdem der Vertragsverletzungs-Handler normal zurückgekehrt ist, sodass jeder andere Vorgang
OP
, der nach der Rückkehr des Vertragsverletzungs-Handlers stattfindet, ebenfalls nach
CP
stattfindet.
Behandlung von Ausnahmen durch Assertions
Wenn der Vertragsbruch auftrat, weil die Auswertung des Prädikats durch eine Ausnahme beendet wurde und die Auswertungssemantik "observe" oder "enforce" ist, wird der Vertragsbruch-Handler innerhalb eines aktiven impliziten Handlers für diese Ausnahme aufgerufen.
Wenn der Vertragsverletzungs-Handler normal zurückkehrt:
- Wenn die Auswertungssemantik "observe" ist, wird der implizite Handler nicht mehr als aktiv betrachtet.
- Wenn die Auswertungssemantik "enforce" ist, bleibt der implizite Handler bei Vertragsbeendigung aktiv.
Die aktuelle Ausnahme kann innerhalb des Vertragsverletzungs-Handlers mit std::current_exception() inspiziert oder erneut ausgelöst werden.
In Reihenfolge auswerten
Um eine Liste
R
von Vertragsassertionen
sequenziell auszuwerten
:
S
, sodass alle folgenden Bedingungen erfüllt sind:
-
Alle Elemente von
Rsind inSenthalten. -
Jedes Element von
Rkann eine implementierungsdefinierte Anzahl von Malen inSwiederholt werden. -
Wenn eine Vertragsassertion
Aeiner anderen VertragsassertionBinRvorausgeht, dann geht das erste Vorkommen vonAdem ersten Vorkommen vonBinSvoraus.
S
so, dass, wenn eine Vertragsassertion
A
einer Vertragsassertion
B
in
S
vorausgeht, dann die Auswertung von
A
vor der Auswertung
von
B
sequenziert ist.
void f(int i) { contract_assert(i > 0); // #1 contract_assert(i < 10); // #2 // gültige Auswertungssequenzen: #1 #2 (keine Wiederholung) // gültige Auswertungssequenzen: #1 #1 #2 #2 (Wiederholung in Sequenz) // gültige Auswertungssequenzen: #1 #2 #1 #2 (alternative Wiederholung) // gültige Auswertungssequenzen: #1 #2 #2 #1 (zweite Vorkommen können Reihenfolge wechseln) // ungültige Auswertungssequenz: #2 #1 (erste Vorkommen können Reihenfolge nicht wechseln) }
Hinweise
Die Bandbreite und Flexibilität der verfügbaren Auswahlmöglichkeiten für Auswertungssemantiken hängt von der Implementierung ab und muss nicht alle vier Auswertungssemantiken als Möglichkeiten zulassen.
Unterschiedliche Auswertungssemantiken, die für dieselbe Vertragsassertion in verschiedenen Übersetzungseinheiten gewählt werden, können zu Verstößen gegen die one-definition rule führen, wenn eine Vertragsassertion Nebeneffekte hat, die den von einem konstanten Ausdruck produzierten Wert verändern:
constexpr int f(int i) { contract_assert((++const_cast<int&>(i), true)); return i; } inline void g() { int a[f(1)]; // Größe abhängig von der Auswertungssemantik von contract_assert oben }
Wenn der Wert, der sich aus der Auswertung des Prädikats ergibt, true ist, tritt keine Vertragsverletzung auf und der Kontrollfluss setzt normal nach dem Auswertungspunkt der Vertragsassertion fort.
Wenn die Auswertung des Prädikats durch Non-local jumps oder Programmbeendigung erfolgt, tritt ebenfalls keine Vertragsverletzung auf.
Es wird vom C++-Standard empfohlen, dass der standardmäßige Vertragsverletzungs-Handler eine Diagnoseausgabe erzeugen sollte, die die relevantesten Inhalte des Arguments geeignet formatiert (ratenbegrenzt für potenziell wiederholte Verletzungen beobachteter Vertragsassertionen), und dann normal zurückkehrt.
| Feature-Test-Makro | Wert | Std | Feature |
|---|---|---|---|
__cpp_contracts
|
202502L
|
(C++26) | Contracts |
Schlüsselwörter
contract_assert , pre , post
Support-Status
|
C++26-Funktion
|
Paper(s)
|
GCC
|
Clang
|
MSVC
|
Apple Clang
|
EDG eccp
|
Intel C++
|
Nvidia HPC C++ (ex PGI)*
|
Nvidia nvcc
|
Cray
|
|---|---|---|---|---|---|---|---|---|---|---|
| Contracts ( FTM ) * | P2900R14 |
Siehe auch
contract_assert
Anweisung
(C++26)
|
überprüft eine interne Bedingung während der Ausführung |
| Funktionsvertragsspezifizierer (C++26) | spezifiziert Vorbedingungen ( pre ) und Nachbedingungen ( post ) |