Skip to content

C++26 Contracts

Overview

Contracts are C++26's language-level code correctness infrastructure, allowing preconditions, postconditions, and assertions to be declared in function interfaces and logic, with standardized violation handling and configurable build modes.

Proposal status: P2900R14 has been accepted for C++26.

Syntax

Preconditions (pre)

cpp
int safe_divide(int a, int b)
    pre (b != 0)
    pre (a >= 0)
{ return a / b; }

Postconditions (post)

cpp
int absolute_value(int x)
    post (r: r >= 0)          // r binds to the return value
{ return x < 0 ? -x : x; }

Assertions (contract_assert)

cpp
void process(std::vector<int>& data) pre (!data.empty()) {
    std::ranges::sort(data);
    contract_assert(std::ranges::is_sorted(data));
}

Violation Handling

cpp
void my_handler(std::contract_violation const& v) {
    std::cerr << "Contract violation at " << v.source_location().line() << "\n";
    if (v.is_terminating()) std::abort();
}
std::set_contract_violation_handler(my_handler);

Build Modes

ModeBehaviorScenario
defaultImplementation-definedGeneral development
ignoreNot evaluated, zero overheadRelease builds
observeEvaluated and handler called, does not terminateLogging/monitoring
bash
g++ -fcontract-mode=observe main.cpp

Comparison with assert/static_assert

Propertyassertstatic_assertContracts
Evaluation timeRuntimeCompile timeRuntime (configurable)
Release buildsRemovedAlways presentOptional
LocationFunction bodyAny declarationFunction interface + function body
Violation handlingabortCompile errorCustom handler
cpp
template <typename T>
T clamp(T val, T lo, T hi) {
    static_assert(std::is_arithmetic_v<T>);   // Compile-time
    assert(lo <= hi);                          // Debug only
    contract_assert(lo <= hi);                // Configurable
    return val < lo ? lo : (val > hi ? hi : val);
}

Virtual Function Contracts

cpp
class Shape {
public:
    virtual double area() const post (r: r >= 0.0);
};

class Circle : public Shape {
    double radius_;
public:
    Circle(double r) : radius_(r) pre (r > 0.0) {}
    double area() const override post (r: r > 0.0)
    { return 3.14159265358979 * radius_ * radius_; }
};

Rule: derived class preconditions must not be stronger (only relaxed), postconditions must not be weaker (only strengthened), ensuring the Liskov Substitution Principle.

Complete Example

cpp
#include <vector>
#include <contract>

class Stack {
    std::vector<int> data_;
public:
    void push(int val) post: !data_.empty()
    { data_.push_back(val); }

    int pop() pre (!data_.empty()) {
        int val = data_.back();
        data_.pop_back();
        return val;
    }

    bool empty() const { return data_.empty(); }
};

int main() {
    Stack s;
    s.push(42);
    contract_assert(!s.empty());
    int val = s.pop();
    contract_assert(val == 42);
}

Implementation Status

CompilerStatus
GCCIn development, partial syntax support
ClangExperimental branch
MSVCNo public implementation yet

Summary

C++26 Contracts elevate correctness checks from macros and comments into a language feature. Through standardized preconditions/postconditions, customizable violation handlers, and three build modes, contracts provide protection during development and operate at zero or controlled overhead in release builds.

Released under the MIT License