Skip to main content

Command Palette

Search for a command to run...

C++26 Contracts Explained: The Feature C++ Developers Have Waited Decades For

Updated
•6 min read•View as Markdown
C++26 Contracts Explained: The Feature C++ Developers Have Waited Decades For
S
Satish Waghole Expert Developer | Automotive Software Architect | Tech Enthusiast

C++26 Contracts: Finally, Native Design-by-Contract Arrives in Modern C++

Introduction

For decades, C++ developers have relied on comments, documentation, assertions, code reviews, and defensive programming to express expectations about how functions should be used. The problem is that comments can become outdated, documentation can be ignored, and assertions are often disabled in release builds.

C++26 introduces Contracts, a language-level feature that allows developers to formally specify preconditions, postconditions, and runtime correctness expectations directly in code.

This article explains Contracts from scratch, why they were added, the problems they solve, practical use cases, and how you can start using them.


What Are Contracts?

A contract is an agreement between a function and its caller.

A contract explicitly states:

  • What must be true before a function is called (Precondition)

  • What must be true after a function completes (Postcondition)

  • What conditions must always remain true during execution (Assertions)

Think of contracts as executable documentation.

Instead of writing:

// Caller must pass a positive value.
int squareRoot(int x);

You can write:

int squareRoot(int x)
    pre(x >= 0);

Now the expectation becomes part of the language itself.


When Were Contracts Added to Standard C++?

Contracts are part of C++26 and are specified as Contract Assertions.

The feature was accepted through WG21 proposal P2900 and appears in the C++26 working draft.

References:


Why Did C++ Need Contracts?

Before C++26, developers generally used one of these approaches:

1. Comments

// age should be >= 18
void registerUser(int age);

Problem:

  • Compiler cannot verify it.

  • Caller may ignore it.

2. Runtime Checks

if(age < 18)
{
    throw std::invalid_argument("Invalid age");
}

Problem:

  • Boilerplate code everywhere.

  • Intent gets mixed with business logic.

3. assert()

assert(age >= 18);

Problem:

  • Often disabled in release builds.

  • Not part of function interface.

Contracts solve all these issues by making expectations explicit and standardized.


Problems Contracts Solve

Problem #1: Hidden Assumptions

Without contracts:

double divide(double a, double b)
{
    return a / b;
}

Does the caller know that b must not be zero?

Not necessarily.

With contracts:

double divide(double a, double b)
    pre(b != 0)
{
    return a / b;
}

The requirement is visible immediately.


Problem #2: Better API Documentation

Contracts make APIs self-documenting.

void withdraw(double amount)
    pre(amount > 0);

Every reader instantly understands the expectation.


Problem #3: Earlier Bug Detection

Many production bugs occur because callers provide invalid inputs.

Contracts detect violations closer to the source of the problem.


Problem #4: Reduced Defensive Programming

Instead of writing repetitive validation code throughout an application, developers can express requirements declaratively.


Core Building Blocks

1. Preconditions

A precondition defines what must be true before the function executes.

int divide(int a, int b)
    pre(b != 0)
{
    return a / b;
}

Meaning:

"The caller is responsible for ensuring b is not zero."


2. Postconditions

A postcondition defines what must be true after execution.

int absoluteValue(int value)
    post(result : result >= 0)
{
    return value < 0 ? -value : value;
}

Meaning:

"The function guarantees the returned value is never negative."


3. contract_assert

Used inside a function body.

void sortData(std::vector<int>& data)
{
    std::ranges::sort(data);

    contract_assert(std::ranges::is_sorted(data));
}

This verifies an important assumption during execution.


Easy Example: Bank Account Withdrawal

Without Contracts

class BankAccount
{
public:
    void withdraw(double amount)
    {
        if(amount <= 0)
        {
            throw std::runtime_error("Invalid amount");
        }

        balance -= amount;
    }

private:
    double balance{1000};
};

With Contracts

class BankAccount
{
public:
    void withdraw(double amount)
        pre(amount > 0)
    {
        balance -= amount;
    }

private:
    double balance{1000};
};

The code becomes cleaner and the intent becomes obvious.


Real-World Use Cases

Financial Systems

void transfer(double amount)
    pre(amount > 0);

Ensures invalid transactions never start.

Automotive Software

void setVehicleSpeed(int speed)
    pre(speed >= 0)
    pre(speed <= 250);

Useful in safety-critical systems.

Embedded Systems

void writeBuffer(std::span<char> data)
    pre(!data.empty());

Prevents invalid memory operations.

Networking

void connect(int port)
    pre(port > 0)
    pre(port <= 65535);

Avoids invalid configuration bugs.


Contracts vs assert()

assert(ptr != nullptr);

versus

void process(Data* ptr)
    pre(ptr != nullptr);

Advantages of Contracts:

  • Part of the public interface

  • Standardized behavior

  • Self-documenting APIs

  • Better tooling support

  • Can participate in contract violation handling


How Contracts Make Life Easier

For API Designers

Requirements become explicit.

For Code Reviewers

Hidden assumptions become visible.

For Test Engineers

Expected behavior is easier to verify.

For New Team Members

Contracts significantly reduce onboarding effort.

For Large Projects

Contracts act as living documentation that remains close to the implementation.


Complete Example

#include <iostream>

int divide(int numerator, int denominator)
    pre(denominator != 0)
    post(result : result <= numerator)
{
    return numerator / denominator;
}

int main()
{
    std::cout << divide(20, 4) << '\n';
}

What this contract says:

  1. Caller must not pass zero.

  2. Function guarantees the postcondition.

  3. Violations are handled through the C++ contract mechanism.


Will Contracts Replace Exceptions?

No.

Exceptions and contracts solve different problems.

Use Contracts when:

  • Caller violates API rules.

  • A programming error occurs.

  • Preconditions are broken.

Use Exceptions when:

  • External failures occur.

  • Network issues happen.

  • Files are missing.

  • Databases are unavailable.


Things to Remember

  • Contracts are not a replacement for input validation.

  • Contracts express programmer assumptions.

  • Contracts improve readability.

  • Contracts help find bugs earlier.

  • Contracts provide executable documentation.

  • Contracts are one of the most anticipated language-level correctness features added to modern C++.


Final Thoughts

C++26 Contracts bring Design by Contract directly into the language. Instead of scattering checks across codebases or relying solely on documentation, developers can now formally state expectations and guarantees in a way that is readable, maintainable, and tool-friendly.

For large-scale systems such as Automotive, Embedded, Finance, Cloud, and Distributed Applications, Contracts can become a powerful mechanism for improving code quality and reducing defects.

As compiler support matures, Contracts may become one of the most impactful C++ features for building reliable software.


Sources

  1. Cppreference - Contract Assertions (C++26) https://cppreference.com/cpp/language/contracts

  2. WG21 C++ Standard Papers (P2900) https://www.open-std.org/

More from this blog

Swapnil Tamhane... मित्रा... तू अजूनही सोबत आहेस

माझ्या प्रिय बालमित्रासाठी ही केवळ कविता नाही, तर बालपणापासून तारुण्यापर्यंत सोबत चाललेल्या मैत्रीची आठवण आहे. अशा वेळी शब्द अपुरे पडतात, पण मनातल्या भावना व्यक्त करण्याचा हा एक छोटासा प्रयत्न. स्वप्न

Oct 7, 20262 min read
Swapnil Tamhane...

मित्रा... तू अजूनही सोबत आहेस

2. Artful living

अयुष्यावर बोलू काही जरा चुकीचे, जरा बरोबर बोलू काही !चला दोस्तहो आयुष्यावर बोलू काही ! उगाच वळसे शब्दांचे हे देत रहा तू भिडले नाहीत डोळे तोवर बोलू काही तुफान पाहुन तीरावर कुजबुजल्या होड्या पाठ फिरू दे

Sep 30, 20261 min read
2. Artful living

Artful living

हे भलते अवघड असते! – संदीप खरे गाडी सुटलि, रुमाल हलले, क्षणात डोळे टचकन ओलेगाडी सुटलि, पडले चेहरे, क्षण साधाया हसरे झालेगाडी सुटलि, हाता मधुनि हात कापरा तरी सुटेनाअंतरातली ओली माया तुटुदे म्हणतले तरी

Sep 30, 20262 min read
Artful living

Code, Cars & Curiosity

6 posts

Exploring technology, life, and everything in between. From software architecture, embedded systems, and AI to health, mindfulness, travel, psychology, poetry, and personal reflections. A place for curious minds who believe learning never stops.