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

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:

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

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 :

1) Konstruieren Sie eine Liste von Vertragsassertionen S , sodass alle folgenden Bedingungen erfüllt sind:
  • Alle Elemente von R sind in S enthalten.
  • Jedes Element von R kann eine implementierungsdefinierte Anzahl von Malen in S wiederholt werden.
  • Wenn eine Vertragsassertion A einer anderen Vertragsassertion B in R vorausgeht, dann geht das erste Vorkommen von A dem ersten Vorkommen von B in S voraus.
2) Bewerten Sie jedes Element von 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 )