Namensräume
Varianten
Aktionen

Vertragszusicherungen (seit C++26)

Von cppreference.com
< cpp‎ | Sprache
 
 
C++ Sprache
Allgemeine Themen
Kontrollfluss
Bedingte Ausführungsaussagen
if
Iterationsanweisungen (Schleifen)
for
Bereichs-for (C++11)
Sprunganweisungen
Funktionen
Funktionsdeklaration
Lambda-Funktionsausdruck
inline-Spezifizierer
Dynamische Ausnahmespezifikationen (bis C++17*)
noexcept-Spezifizierer (C++11)
Ausnahmen
Namensräume
Typen
Spezifizierer
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Speicherdauer-Spezifizierer
Initialisierung
Ausdrücke
Alternative Darstellungen
Literale
Boolesch - Ganzzahl - Gleitkommazahl
Zeichen - String - nullptr (C++11)
Benutzerdefinierte (C++11)
Dienstprogramme
Attribute (C++11)
Typen
typedef-Deklaration
Typalias-Deklaration (C++11)
Umwandlungen
Speicherzuweisung
Klassen
Klassenspezifische Funktionseigenschaften
explicit (C++11)
static

Spezielle Member-Funktionen
Templates
Sonstiges
 
 

Vertragszusicherungen ermöglichen es dem Programmierer, Eigenschaften des Programmzustands anzugeben, die an bestimmten Punkten während der Ausführung gelten sollen.

Inhalt

[edit] Erklärung

Vertragszusicherungen werden durch Funktionsvertragspezifizierer und contract_assert-Anweisungen eingeführt. Jede Vertragszusicherung hat ein Prädikat , das ein Ausdruck vom Typ bool ist.

[edit] Auswertung von Vertragszusicherungen

Eine Auswertung einer Vertragszusicherung verwendet eine der folgenden Auswertungssemantiken

 Auswertungssemantik   Prüfsemantik   Terminierende Semantik 
ignorieren
beobachten Ja
erzwingen Ja Ja
schnell-erzwingen Ja Ja

Es liegt in der Implementierungsdefinition, welche Auswertungssemantik für eine gegebene Auswertung einer Vertragszusicherung verwendet wird. Die Auswertungssemantiken können für verschiedene Auswertungen derselben Vertragszusicherung unterschiedlich sein, einschließlich Auswertungen während der konstanten Auswertung.

Wenn die Semantik "ignorieren" verwendet wird, hat die Auswertung einer Vertragszusicherung keine Auswirkung.

Wenn eine Prüfsemantik verwendet wird, bestimmt die Auswertung E einer Vertragszusicherung den Wert des Prädikats. Ob das Prädikat ausgewertet wird, ist nicht spezifiziert. 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 endet über eine Ausnahme.
  • Die Auswertung des Prädikats erfolgt in einem Kontext, der manifestiert konstant ausgewertet ist und das Prädikat keine Kern-Konstantausdruck ist.

Es gibt einen beobachtbaren Kontrollpunkt CP, der vor E liegt, so dass jede andere Operation OP, die vor A stattfindet, auch vor CP stattfindet.

int num = 0;
void f() pre((num++, false));
 
f(); // Increment of “num” might not occur, even if a checking semantic is used

[edit] Behandlung von Vertragsverletzungen

Wenn eine Vertragsverletzung in einem Kontext auftritt, der manifestiert konstant ausgewertet wird

  • Wenn die Auswertungssemantik "beobachten" ist, wird eine Diagnose ausgegeben.
  • Wenn die Auswertungssemantik eine terminierende Semantik ist, ist das Programm schlecht formuliert.

Wenn eine Vertragsverletzung in einem Kontext auftritt, der nicht manifestiert konstant ausgewertet wird

  • Wenn die Auswertungssemantik "schnell-erzwingen" ist, wird das Programm mit einem Vertrag beendet.
  • Wenn die Auswertungssemantik "erzwingen" oder "beobachten" ist, wird die Vertragsverletzungsbehandlungsroutine mit einem L-Wert aufgerufen, der auf ein Objekt obj vom Typ const std::contracts::contract_violation verweist, das Informationen über die Vertragsverletzung enthält.
    • Der Speicher für obj wird auf nicht spezifizierte Weise zugewiesen, aber es wird keine globale Allokationsfunktion aufgerufen.
    • Die Lebensdauer von obj dauert für die Dauer des Aufrufs der Vertragsverletzungsbehandlungsroutine an.

[edit] Vertragsbeendete Programme

Wenn das Programm vertragsbeendet  ist, liegt es in der Implementierungsdefinition (abhängig vom Kontext), ob

[edit] Vertragsverletzungsbehandlungsroutine

Die Vertragsverletzungsbehandlungsroutine eines Programms ist eine Funktion namens ::handle_contract_violation

void handle_contract_violation( std::contracts::contract_violation );
(seit C++26)
(optional noexcept)

Eine Definition der Vertragsverletzungsbehandlungsroutine, die als Standard-Vertragsverletzungsbehandlungsroutine  bezeichnet wird, wird von der Implementierung bereitgestellt (anstelle einer Standardbibliotheksüberschrift).

Es liegt in der Implementierungsdefinition, ob die Vertragsverletzungsbehandlungsroutine ersetzbar ist. Wenn die Vertragsverletzungsbehandlungsroutine nicht ersetzbar ist, ist eine Deklaration einer Ersetzungsfunktion für die Vertragsverletzungsbehandlungsroutine schlecht formuliert, keine Diagnose erforderlich.

Wenn die Vertragsverletzungsbehandlungsroutine normal zurückkehrt

  • Wenn die Auswertungssemantik "beobachten" ist, wird der Kontrollfluss nach dem Auswertungspunkt der Vertragszusicherung normal fortgesetzt.
  • Wenn die Auswertungssemantik "erzwingen" ist, wird das Programm mit einem Vertrag beendet.

Es gibt einen beobachtbaren Kontrollpunkt CP, der nach der normalen Rückkehr der Vertragsverletzungsbehandlungsroutine liegt, so dass jede andere Operation OP, die nach der Rückkehr der Vertragsverletzungsbehandlungsroutine stattfindet, auch nach CP stattfindet.

[edit] Behandlung von Ausnahmen von Zusicherungen

Wenn die Vertragsverletzung dadurch aufgetreten ist, dass die Auswertung des Prädikats über eine Ausnahme beendet wurde und die Auswertungssemantik "beobachten" oder "erzwingen" ist, wird die Vertragsverletzungsbehandlungsroutine innerhalb eines aktiven impliziten Handlers für diese Ausnahme aufgerufen.

Wenn die Vertragsverletzungsbehandlungsroutine normal zurückkehrt

  • Wenn die Auswertungssemantik "beobachten" ist, wird der implizite Handler nicht mehr als aktiv betrachtet.
  • Wenn die Auswertungssemantik "erzwingen" ist, bleibt der implizite Handler aktiv, wenn die Vertragsbeendigung eintritt.

Die aktuelle Ausnahme kann innerhalb der Vertragsverletzungsbehandlungsroutine mit std::current_exception() inspiziert oder erneut ausgelöst werden.

[edit] Sequentielle Auswertung

Um eine Liste R von Vertragszusicherungen sequentiell auszuwerten

1) Konstruieren Sie eine Liste von Vertragszusicherungen S, so dass alle folgenden Bedingungen erfüllt sind
  • Alle Elemente von R sind in S enthalten.
  • Jedes Element von R kann eine von der Implementierung definierte Anzahl von Malen innerhalb von S wiederholt werden.
  • Wenn eine Vertragszusicherung A einer anderen Vertragszusicherung B in R vorausgeht, dann geht die erste Instanz von A der ersten Instanz von B in S voraus.
2) Werten Sie jedes Element von S so aus, dass, wenn eine Vertragszusicherung A einer Vertragszusicherung B in S vorausgeht, die Auswertung von A sequenziert vor der Auswertung von B erfolgt.
void f(int i)
{
    contract_assert(i > 0);  // #1
    contract_assert(i < 10); // #2
    // valid sequence of evaluations:   #1 #2       (no repeat)
    // valid sequence of evaluations:   #1 #1 #2 #2 (repeat in sequence)
    // valid sequence of evaluations:   #1 #2 #1 #2 (repeat alternatively)
    // valid sequence of evaluations:   #1 #2 #2 #1 (second occurences can switch order)
    // invalid sequence of evaluations: #2 #1       (first occurences cannot switch)
}

[edit] Anmerkungen

Der Bereich und die Flexibilität der verfügbaren Auswahlmöglichkeiten für Auswertungssemantiken hängen von der Implementierung ab und müssen nicht alle vier Auswertungssemantiken als Möglichkeiten zulassen.

Unterschiedliche Auswertungssemantiken, die für dieselbe Vertragszusicherung in verschiedenen Übersetzungseinheiten gewählt werden, können zu Verstößen gegen die Ein-Definitions-Regel führen, wenn eine Vertragszusicherung 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)]; // size dependent on the evaluation semantic of contract_assert above
}

Wenn der Wert, der sich aus der Auswertung des Prädikats ergeben würde, true ist, tritt keine Vertragsverletzung auf und der Kontrollfluss wird nach dem Auswertungspunkt der Vertragszusicherung normal fortgesetzt.

Wenn die Auswertung des Prädikats mittels nicht-lokaler Sprünge oder der Beendigung des Programms beendet wird, tritt ebenfalls keine Vertragsverletzung auf.

Der C++-Standard empfiehlt, dass die Standard-Vertragsverletzungsbehandlungsroutine diagnostische Ausgaben erzeugt, die die relevantesten Inhalte des Arguments (ratenbegrenzt für potenziell wiederholte Verletzungen beobachteter Vertragszusicherungen) zweckmäßig formatiert und dann normal zurückkehrt.

Feature-Testmakro Wert Std Feature
__cpp_contracts 202502L (C++26) Verträge

[edit] Schlüsselwörter

contract_assert, pre, post

[edit] Siehe auch

contract_assert-Anweisung (C++26) verifiziert eine interne Bedingung während der Ausführung[edit]
Funktionsvertragspezifizierer (C++26) spezifiziert Vorbedingungen (pre) und Nachbedingungen (post)[edit]