Skip to content

C++ Support

This page is a reference of the C++ language features and standard-library headers supported by ESBMC’s Clang-based C++ frontend. For what is not supported, see Limitations.

At a glance

StandardLanguage featuresLibraryRegression suite
C++98 / C++03FullContainers, streams, stringsregression/esbmc-cpp
C++11FullMove semantics, smart pointers, <chrono>, <atomic>, <thread>regression/esbmc-cpp11
C++14Fullstd::make_uniqueregression/esbmc-cpp14
C++17Fullstd::optional, std::variant, std::any, std::string_viewregression/esbmc-cpp17
C++20Broadstd::span, <compare>, std::source_locationregression/esbmc-cpp20
C++23Selectedstd::expectedregression/esbmc-cpp20

The default is C++17. Select a different standard with --std, for example --std c++20 or --std c++03.

Support is not gap-free at any standard — see Limitations for the known exceptions, notably constructor and destructor ordering.

Verifying a C++ program

ESBMC checks memory safety, arithmetic overflow, pointer safety and user assertions across all inputs, rather than the single input a test would exercise. Given shape.cpp:

#include <cassert>

class Shape
{
public:
  virtual int area() const = 0;
  virtual ~Shape() = default;
};

class Square : public Shape
{
  int side;

public:
  Square(int s) : side(s) {}
  int area() const override { return side * side; }
};

int main()
{
  int n = nondet_int();
  __ESBMC_assume(n >= 1 && n < 100);

  Shape *s = new Square(n);
  assert(s->area() > n);
  delete s;
  return 0;
}

Run it with:

esbmc shape.cpp --incremental-bmc

ESBMC finds the one input that breaks the assertion — n == 1, where 1 * 1 is not greater than 1:

[Counterexample]

State 1 file shape.cpp line 21 column 3 function main thread 0
----------------------------------------------------
  n = 1 (00000000 00000000 00000000 00000001)

State 5 file shape.cpp line 25 column 3 function main thread 0
----------------------------------------------------
Violated property:
  file shape.cpp line 25 column 3 function main
  assertion main
  !((_Bool)((signed long int)(!(return_value$ > n))))

VERIFICATION FAILED

Tightening the assumption to n > 1 makes the property hold for every one of the remaining inputs, and ESBMC reports VERIFICATION SUCCESSFUL.

See the Usage guide for the full set of options and the Constructs reference for __ESBMC_assume, nondet_int and the other verification annotations.

Operational models vs. host headers

By default ESBMC compiles C++ with -nostdinc++, so #include <vector> resolves to ESBMC’s own operational model (OM) rather than your host standard library. OMs are written to be verification-friendly — small, loop-free where possible, and free of the inline assembly and compiler intrinsics that real standard-library implementations rely on.

Two flags change this behaviour:

FlagEffect
--no-abstracted-cpp-includesDo not include the abstract C++ operational models at all.
--mix-cpp-host-headersKeep the host system headers visible alongside the OMs, so an #include not covered by the bundled models falls through to the host header.

--mix-cpp-host-headers is the escape hatch for a header ESBMC does not model (see Not modelled below). It is opt-in because names defined by both the OMs and the host library — char_traits, istream and similar — can then produce ambiguity errors at parse time.

Language features

Classes and objects

  • Classes, member functions, member access control
  • Constructors and destructors, including default, copy and move forms
  • Static and non-static data members; default member initialisers
  • Unions, including anonymous unions
  • typeid on a polymorphic glvalue reports the dynamic type, and the type_info name string is NUL-terminated

Constructors and destructors

  • Delegating and inheriting constructors (using Base::Base;), including multi-base and chained forms
  • Virtual bases are initialised only in the most-derived constructor
  • Destructor chains for members and bases, including virtual base destructors
  • Destructors run on return paths, for discarded results, and for temporaries destroyed mid-expression
The order in which constructors and destructors run is not correct in every case. See Limitations.

References, temporaries and move semantics

  • Lvalue and rvalue references
  • Move constructors and move assignment operators
  • Address-of distributes over a conditional lvalue; class-typed conditionals elide their temporaries; a reference parameter binds to the selected arm

Templates

  • Class and function templates, partial and explicit specialisation
  • Variable templates (C++14) and variable template declarations (C++17)
  • Class template argument deduction (CTAD)
  • Concepts and requires clauses (C++20)

Inheritance and polymorphism

  • Single-level and multi-level polymorphism
  • Pure virtual methods and abstract classes
  • Virtual inheritance, including the diamond problem
  • Multiple inheritance: nested base subobjects, dynamic_cast<T*> re-offsetting across bases, override thunks keyed by each base’s virtual name and adjusted by the indirect base’s cumulative offset, and catch-by-base binding re-offset for multiple-inheritance thrown types
  • Virtual dispatch through a non-arrow member expression — (*p).f() and ref.f() dispatch virtually

Memory management

  • new / delete and new[] / delete[]
  • Detection of dangling pointers, double delete and mismatched operators
  • Placement new, including the form without an initialiser
  • delete dispatches through the virtual destructor slot; deleting through a base subobject whose destructor is not virtual is rejected

Exceptions

try / catch / throw are supported directly. Passing --lower-exceptions additionally lowers exception handling into explicit control flow, which enables:

  • noexcept and throw() exception specifications
  • Dynamic exception specifications, with unexpected / bad_exception recovery
  • std::exception_ptr with current_exception, rethrow_exception and make_exception_ptr, plus nested exceptions (throw_with_nested, rethrow_if_nested)
  • std::uncaught_exception / std::uncaught_exceptions, via a lowered per-thread count

Other exception behaviour:

  • dynamic_cast<T&> throws std::bad_cast on a failed reference cast
  • std::vector::at and std::string::at throw std::out_of_range rather than asserting
  • std::bad_cast and std::bad_typeid derive from std::exception with a virtual what()
  • The exception-state globals are thread-local, so each thread raises, catches and clears its own in-flight exception independently; concurrently-throwing programs are lowered rather than rejected

Selected C++17 / C++20 / C++23 features

FeatureStandard
Structured bindings, including binding by reference and over std::tupleC++17
Three-way comparison <=>, including pointer and side-effecting operandsC++20
Parenthesized aggregate initializationC++20
using enum declarationsC++20
char8_tC++20
Explicit object parameter (“deducing this”), including mutating receiversC++23
static operator(), with the implicit object argument skippedC++23

Standard-library coverage

The headers below are modelled by ESBMC’s own operational models and are covered by regression tests under regression/esbmc-cpp*.

Containers and iterators

HeaderNotes
<vector>Including data(), emplace_back, shrink_to_fit, cbegin/cend; the destructor frees its buffer
<list>Const front/back/rbegin/rend, cbegin/cend
<deque>Const iteration
<map>Const at, emplace, try_emplace, insert_or_assign, C++20 contains
<set>Const-correct const iterators, emplace, C++20 contains
<unordered_map>, <unordered_set>
<array>iterator / const_iterator typedefs; usable in C++11
<queue>, <stack>, <bitset>Includes std::priority_queue
<iterator>iterator_traits and the iterator tags
<valarray>

std::multimap and std::multiset track std::map and std::set, including contains and cbegin/cend.

Strings and streams

HeaderNotes
<string>(const char*, size_t) range and fill constructors; length-aware operator</operator> including free overloads against const char*; const substr(pos, n); C++20 starts_with/ends_with; at throws std::out_of_range
<string_view>Search members, stringstring_view conversion, hash<string_view>
<iostream>, <istream>, <ostream>, <ios>, <iosfwd>Standard stream objects, ios::widen/narrow, ios::exceptions, ios::copyfmt
<sstream>, <fstream>, <streambuf>, <iomanip>
<locale>

Utilities and type support

HeaderNotes
<type_traits>Classification traits and the _t aliases
<utility>, <functional>, <memory>, <initializer_list>
<tuple>std::tie, std::ignore, structured binding over a tuple
<optional>emplace, swap, std::make_optional
<variant>, <any>The converting constructor does not hijack copies
<expected>C++23
<compare>Includable before C++20
<source_location>, <span>, <bit>C++20
<typeinfo>, <exception>, <stdexcept>, <system_error>, <new>
<limits>Works under --std c++11 and c++14
<filesystem>

Algorithms and numerics

HeaderNotes
<algorithm>Including the C++11 algorithms
<numeric>iota, gcd, lcm, reduce
<cmath>The floating-point classifiers std::isnan, std::isinf, std::isfinite, std::isnormal and std::signbit are re-declared as std:: overloads lowered to ESBMC’s native FP intrinsics
<complex>, <random>, <chrono><chrono> covers durations

Concurrency

<thread>, <mutex> and <condition_variable> are lowered onto ESBMC’s pthread model, so interleaving exploration, deadlock detection and data-race detection apply to std::thread programs. std::promise and std::future are modelled on the same basis, and <atomic> is modelled with atomic sections.

C library headers

<cassert>, <cctype>, <cerrno>, <cfloat>, <ciso646>, <climits>, <clocale>, <cmath>, <csetjmp>, <csignal>, <cstdarg>, <cstddef>, <cstdint>, <cstdio>, <cstdlib>, <cstring> and <ctime> are available.

Standard-version guards

<compare> is includable before C++20; <bit>, <span> and <expected> are guarded by standard version; <array> is usable in C++11; <limits> works under --std c++11 and c++14; and the C++98 container headers parse under --std c++03.

Not modelled

The following standard headers have no operational model. Including one either fails to resolve, or falls through to your host header under --mix-cpp-host-headers — in which case ESBMC has to verify the real implementation, which is frequently intractable.

<forward_list>, <regex>, <ranges>, <format>, <concepts>, <coroutine>, <charconv>, <numbers>, <ratio>, <typeindex>, <shared_mutex>, <barrier>, <latch>, <semaphore>, <stop_token>, <syncstream>, <execution>, <memory_resource>, <scoped_allocator>, <cwchar>, <cwctype>, <cfenv>, <cinttypes>.

Note that <concepts> being unmodelled does not affect the language feature — concepts and requires clauses are supported, as listed above.

Current status

Feature support is tracked on the issue tracker under the C++ label. For the current pass rate, run the esbmc-cpp* regression suites or consult the CI results.

Maintainers: see C++ Workflow and Resources for benchmark tracking and the development workflow.