C++ — Reference
Source: https://en.cppreference.com/w/cpp
C++
- Created: 1979 (as “C with Classes”) by Bjarne Stroustrup at Bell Labs; renamed C++ in 1983
- Latest stable: C++23 (ISO/IEC 14882:2024, published 2024); C++26 in progress
- Paradigms: multi-paradigm — procedural, object-oriented, generic, functional, metaprogramming
- Typing: static, nominal, with type inference (
auto), concepts (C++20) - Memory: manual (RAII + smart pointers); no GC
- Compilation: AOT compiled to native, separate compilation + link
- Primary domains: systems, embedded, games (engines), HFT/trading, browsers, OS kernels, scientific computing, GPU/CUDA hosts
- Official docs: https://en.cppreference.com/w/cpp ; https://isocpp.org/
1. At a glance
- Standardized by ISO/IEC JTC1/SC22/WG21. Three-year cadence: C++17 (2017), C++20 (2020 — modules, concepts, ranges, coroutines), C++23 (2024 —
import std,std::expected,std::print, mdspan), C++26 (publication 2026 — reflection, sender/receiver, contracts, profiles). - Major implementations: GCC (libstdc++ — Linux default, conservative), Clang/LLVM (libc++ — Apple default, Android, fast feature uptake), MSVC (Microsoft STL — open-source since 2019), Apple Clang (lags ~1yr behind upstream), Intel oneAPI DPC++ (SYCL + CUDA-like), NVIDIA HPC SDK (former PGI). Pre-historical: EDG (frontend for many embedded compilers).
- Backwards-compatible with C at the source/ABI boundary (mostly — C++20 designated initializers narrowed the gap; some C constructs like flexible array members aren’t directly supported); routinely used to host other languages’ runtimes (V8, SpiderMonkey, JSC, CPython internals, JVM HotSpot, Lua C++ wrappers, ART/Dalvik).
- Tooling rebooted around LSP via
clangd(LLVM project, the universal C++ LSP — VS Code, Neovim, Emacs, JetBrains) and modules in C++20+.cclshistoric alternative. Source-Based Code Coverage in Clang (-fprofile-instr-generate -fcoverage-mapping). - ABI stability is a perennial topic — neither GCC’s libstdc++ nor Clang’s libc++ guarantees ABI across major versions; cross-vendor STL mixing is unsupported. C++ Committee deliberately broke ABI in C++23 for
std::regex(rejected at last minute); ABI conservatism is a major reason C++ evolves slower than peers.
2. Getting started
-
Install: Linux:
apt install g++ordnf install gcc-c++. macOS:xcode-select --install(Apple Clang). Windows: Visual Studio Build Tools or MSYS2/MinGW-w64. Cross-platform: download from https://gcc.gnu.org/ or https://releases.llvm.org/. -
Version managers: none official. Use distro packages, Homebrew (
brew install llvm), or Conan/vcpkg toolchain files.nix-shell/ Docker for reproducibility. Compiler matrix as of 2026: GCC 15 (full C++23, partial C++26 reflection); Clang 19 (full C++23, partial C++26 + experimental reflection); MSVC 19.42 / VS 17.12 (full C++23 //std:c++latest); Apple Clang lags ~1 year behind upstream Clang. -
Hello, world (C++23):
import std; // C++23 standard-library module int main() { std::println("Hello, world!"); }Compile:
g++ -std=c++23 hello.cpp -o helloorclang++ -std=c++23 -fmodules hello.cpp. Project file equivalent (CMake 3.30+):cmake_minimum_required(VERSION 3.30) project(hello CXX) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_executable(hello hello.cpp) -
Project layout: no enforced layout. Common:
src/,include/<project>/,tests/,CMakeLists.txt. CMake’s “modern target-based” style is dominant — declareadd_library(foo ...)+target_include_directories(foo PUBLIC include), consumerstarget_link_libraries(bar PRIVATE foo)and propagation is automatic. -
Build tools: CMake 3.30+ is de facto (target-based, presets, FetchContent, FILE_SET for modules); Meson (Python config, fast — used by GNOME, systemd, Mesa, GStreamer); Bazel (Google, hermetic, monorepo); xmake (Lua config, batteries-included); Make; Ninja (low-level, used as backend for CMake/Meson — produces optimal incremental builds). Package managers: vcpkg (Microsoft, 2400+ ports, manifest mode
vcpkg.json) and Conan 2 (JFrog, Python config, binary cache via Artifactory/CCI), plus CPM.cmake (CMake-only wrapper around FetchContent), Hunter, build2. -
REPL/playground: Cling / xeus-cling (Jupyter, LLVM-based interpreter); Compiler Explorer (godbolt.org — every compiler, every version, view asm output side-by-side); C++ Insights (cppinsights.io — shows AST and what the compiler “actually” sees, esp. useful for templates / coroutines / structured bindings).
3. Basics
- Primitives:
bool,char/wchar_t/char8_t/char16_t/char32_t, fixed-widthint8_t…int64_t(via<cstdint>),float/double/long double, C++23 extended floating-pointstd::float16_t/std::bfloat16_t/std::float32_t/std::float64_t/std::float128_t. Literals:0x,0b,0(octal), digit separators1'000'000(C++14), raw stringsR"(...)", user-defined literals42_km, type-deduced literal suffixes42u,3.14f,42uz(C++23size_t). - Variables:
auto x = 1;(deduced),const(immutable),constexpr(compile-time const, also fns),consteval(immediate fn — must run at compile time, C++20),constinit(initialized at compile time, no static init order fiasco, C++20). Block scope; RAII destruction in reverse construction order. Class Template Argument Deduction (CTAD, C++17):std::pair p(1, 'a');instead ofstd::pair<int, char>. - Control flow:
if/else,if constexpr(compile-time conditional, branches not taken are not instantiated — replaces SFINAE for many cases),if consteval(C++23),switch(with[[fallthrough]]since C++17),for, range-forfor (auto& x : v), init-statements in if/switch (C++17:if (auto it = map.find(k); it != map.end()) {...}),while,do-while, structured bindingsauto [k, v] = pair;(C++17),auto [k, v] : mapfor map iteration. - Functions: default args, overloading, templates,
autoreturn type (C++14), trailing return typeauto f() -> int, deducingthis(C++23 —auto& f(this auto& self) { ... }for CRTP without the boilerplate). Lambdas[capture](args) -> ret { ... }; generic lambdas[](auto x){...}(C++14); templated lambdas[]<class T>(T x){...}(C++20); static lambdas (C++23 — no captures, no implicitthis). First-class viastd::function/ function pointers.std::function_ref(C++26) for non-owning callable references. - Strings:
std::string(owning, SBO 15-22 chars depending on STL),std::string_view(non-owning, C++17 — careful with lifetimes),std::format(C++20),std::print/println(C++23). No native interpolation; usestd::format("{} {}", a, b)orstd::print("{:>10.2f}\n", pi). C++26 is bringing more:std::formatwith runtime format strings (currently compile-time only withoutvformat), embedded escape handling. - Collections:
std::array<T, N>(stack),std::vector(dynamic, contiguous),std::deque(double-ended, segmented),std::list/std::forward_list(rarely the right choice),std::map/std::unordered_map,std::set/std::unordered_set,std::tuple,std::pair,std::span(C++20 — non-owning contiguous view),std::mdspan(C++23 — multi-dim non-owning),std::flat_map/std::flat_set/std::flat_multimap/std::flat_multiset(C++23 — sorted-vector-based, far better cache behavior than tree-based for ≤~100 elements). External:absl::flat_hash_map(3x faster thanstd::unordered_map),folly::F14,boost::container::flat_map.
4. Intermediate
- Generics: templates over types, non-type values, and template templates. C++20 concepts constrain templates:
template<std::integral T>. CTAD (Class Template Argument Deduction). Variadic templates + parameter packs. Abbreviated function templates:void f(auto x)is shorthand fortemplate<typename T> void f(T x). - Modules: C++20
export module foo;/import foo;.import std;(C++23) replaces<iostream>etc. Build-system support is still maturing — CMake 3.28+ (target_sources(foo PUBLIC FILE_SET CXX_MODULES FILES bar.cppm)) with Ninja 1.11+ for module-dependency scanning (P1689 protocol). Compiler support: Clang 16+, GCC 14+ (partial), MSVC 19.30+. Modules emit a BMI (binary module interface,.pcmfor Clang,.ifcfor MSVC) that’s reused across TUs. - Namespaces:
namespace foo { ... }, nestednamespace foo::bar, anonymous namespaces for TU-local symbols,usingdeclarations and directives.inline namespacefor ABI versioning (std::__1::in libc++). - Error handling: exceptions (
throw/try/catch);std::expected<T,E>(C++23) for value-or-error with monadic opsand_then/or_else/transform/transform_error;std::optional<T>with monadic ops too; assertions via<cassert>and the proposed contracts in C++26.noexceptparticipates in overload resolution and codegen —std::vector::push_backusesnoexcept(is_nothrow_move_constructible_v<T>)to decide whether to move or copy on grow. - Concurrency:
std::thread,std::jthread(C++20, joins on dtor + cancellation token viastd::stop_token),std::mutex/std::shared_mutex,std::atomic<T>,std::atomic_ref<T>(C++20, atomic operations on non-atomic memory),std::condition_variable,std::future/std::async. Synchronization primitives (C++20):std::latch(one-shot countdown),std::barrier(reusable),std::counting_semaphore<N>. Coroutines (C++20):co_await/co_yield/co_return.std::generator(C++23). Parallel STL:std::execution::par/par_unseq/unseq— GCC/Clang use TBB; MSVC uses its own. - I/O & networking:
<iostream>,<fstream>,std::filesystem(C++17),<print>(C++23 —std::print("hello {}\n", name)thread-safe). No standard networking yet (std::netdeferred to C++26+); use Asio (standalone orBoost.Asio), liburing for Linux io_uring, libuv for cross-platform event loop. - Stdlib highlights:
<ranges>(C++20) views & pipelines (v | views::filter(odd) | views::transform(sq) | ranges::to<vector>()),<chrono>(calendars, time zones, parsing in C++20 withstd::chrono::parse),<format>(std::format("{:>10.2f}", 3.14)),<source_location>(line/file/function info without macros),<bit>(std::popcount,std::countl_zero,std::rotl),<numbers>(pi_v<T>,e_v<T>),<random>,<regex>,<stacktrace>(C++23 —std::stacktrace::current()),<mdspan>(C++23 — multi-dimensional non-owning view),<flat_map>/<flat_set>(C++23 — sorted-vector-based, better cache behavior than tree-based).
5. Advanced
- Memory model: explicit. Use
std::unique_ptr/std::shared_ptr/std::weak_ptrovernew/delete. Custom allocators viaAllocatorconcept;std::pmr::polymorphic_allocatorfor arena-style with runtime polymorphism (monotonic_buffer_resource,unsynchronized_pool_resource,synchronized_pool_resource). Alignment viaalignas/alignof. Memory order (memory_order_*) on atomics; the C++ memory model (since C++11) defines happens-before with sequenced-before, synchronizes-with, modification order. Object lifetime rules aroundstd::launder, placement new, implicit-lifetime types (C++20),std::start_lifetime_as(C++23). - Concurrency deep dive: atomics with explicit memory order, lock-free queues,
std::stop_tokencooperative cancellation, executors (TS/proposed),std::latch/std::barrier(C++20). C++26 addsstd::execution(sender/receiver model, P2300 — async composition that subsumes futures, channels, and coroutines),std::hazard_pointer/std::rcufor lock-free deletion, parallel sort scheduling,std::async_scope. Lock-free libraries:folly::ProducerConsumerQueue,boost::lockfree,moodycamel::ConcurrentQueue(mpmc, fastest). - FFI:
extern "C"for C linkage. Direct interop with C; complex with other languages via C wrappers, SWIG, pybind11 + nanobind (Python — nanobind is 4x smaller bindings + 6x faster JIT), cppyy (auto-bindings via Cling), CXX + autocxx (Rust — type-safe bidirectional, used at Mozilla, Google), JNI (Java) / Project Panama FFM (modern), N-API / node-addon-api (Node), WebAssembly via emscripten or Cheerp. - Reflection: none in C++23 beyond
typeid/std::source_location/<type_traits>. Static reflection (^^,[: :], P2996) is targeted for C++26 — Clang has an experimental implementation as of 2024-25. The Reflection TS proposed for C++23 was rejected in favor of P2996’s cleaner design. Compile-time reflection will subsume most TMP / macro use cases (serialization, GUI binding, ORM mapping, ABI dump). - Performance tooling:
perf(Linux, sampling profiler), Intel VTune (microarchitectural events, top-down analysis), AMD uProf, valgrind/cachegrind/callgrind (instrumented, slow but exact), heaptrack (allocation profiler), gperftools (Google), Tracy (frame profiler for games, sub-ns precision), Optick, Easy Profiler, Visual Studio Profiler (Windows), Xcode Instruments (macOS). Sanitizers (-fsanitize=address,undefined,thread,memory,leak,dataflow,hwaddress) — ASan + UBSan are mandatory in CI for any new C++ code in 2026.[[nodiscard]],[[likely]]/[[unlikely]](C++20),__builtin_expect,[[assume]](C++23). PGO (-fprofile-generate/-fprofile-use, typically 5-20% wins), LTO (-flto), ThinLTO (parallel, scales to large monorepos). Post-link optimization: BOLT (Meta — 5-15% wins on top of PGO+LTO), Propeller (Google), AutoFDO. - Build acceleration: ccache (cache by source hash), sccache (Mozilla, distributed, S3/Redis backend), distcc (distributed compilation), icecream (LLVM-aware distributed), FASTBuild, EngFlow / Goma / Bazel remote cache for monorepos. Typical 5-20x speedup on incremental builds.
6. God mode
- Templates as a Turing-complete metalanguage: SFINAE →
enable_if→ C++20 concepts +requiresclauses. CRTP (template<class D> struct Base { auto& self() { return static_cast<D&>(*this); } }). Deducing this (C++23) replaces most CRTP —auto& self(this auto& self). Compile-time TMP libraries:boost::mp11,boost::hana(Louis Dionne, value-based metaprogramming),brigand,metal,kvasir::mpl,frozen(compile-timestd::unordered_map),ctre(compile-time regex, Hana Dusíková — single-header, faster than runtime regex). constexpr/consteval/constinit: entire algorithms run at compile time;constevalrequires immediate evaluation. C++20 allowsstd::vectorandstd::stringin constexpr. C++23 addedif consteval(cleaner alternative tostd::is_constant_evaluated()). C++26 addsconstexprcast fromvoid*, broader floating-point support,constexpr std::function.- Coroutines machinery: customize via
promise_type(return type,initial_suspend/final_suspend,await_transform); awaitables implementawait_ready/await_suspend/await_resume. Stackless, heap-allocated by default — HALO (Heap Allocation eLision Optimization) often elides it. Coroutine libraries:cppcoro(Lewis Baker),folly::coro(Meta),unifex(sender/receiver implementation), Asio C++20 awaitables,libunifex. - Modules + header units:
import <vector>;produces a BMI (binary module interface). Build systems must scan forimport/moduledeclarations (P1689) — CMake/Ninja support is mandatory. GCC 14+, Clang 16+, MSVC 19.30+ all support C++20 modules; ecosystem (Boost, Qt, libfmt) shipping module interfaces through 2025-26. Header units (import <header>;) bridge legacy#include. - Reflection (C++26):
^^Tproduces a reflection value (astd::meta::info);[: e :]splices it back into source. P2996 is the merged proposal; Clang-experimental builds available. Will subsume most TMP, codegen macros, and tools likeboost::pfr/magic_enum. - Placement new + EBO (Empty Base Optimization) +
[[no_unique_address]](C++20,[[msvc::no_unique_address]]for MSVC ABI compat) for zero-overhead composition. Pairs with stateless allocators / unit-struct policies to give zero-overhead generics. std::launder: required to bless pointers after object lifetime tricks (e.g., reusing storage via placement new of a different type). Gets right answer where compilers would assume aliasing-free.- Custom allocators:
Allocatorconcept,std::pmrfor runtime polymorphism, NUMA-aware allocation, slab/arena allocators. Mimalloc (Microsoft), jemalloc (Meta/FreeBSD), tcmalloc (Google), rpmalloc, snmalloc (Microsoft) — typical 5-30% speedups over defaultglibcmalloc on multi-threaded allocators. - Link-time tricks:
--gc-sections(drop unused code),--icf=safe/--icf=all(identical-code-folding — Chromium saves 10-15 MB), section-based code layout (-ffunction-sections -fdata-sections), BOLT (Meta’s post-link binary optimizer, 5-15% on top of PGO), Propeller (Google), Embedded ELF. - UB catalog awareness: signed overflow, OOB access, use-after-free, strict aliasing violations, unsequenced modifications, data races, type-punning via pointer cast (use
std::bit_castC++20 instead), reading uninitialized memory, integer divide by zero, invalidnullptrdereference, exceedingvector::reserve, doubledelete, returning ref to local. Use UBSan/ASan/MSan/TSan religiously. CFI (Control Flow Integrity):-fsanitize=cfi+ LTO catches indirect-call type confusion. - Embedding: C++ embeds well into anything that takes a C ABI; the runtime dependencies are minimal (
libstdc++/libc++,libgcc/compiler-rt, libc). For tiny embedded:-fno-exceptions -fno-rtti -nostdlib++and bring your own minimalstd.
Standard library implementations
- libstdc++ (GCC) — Linux default, conservative, mature. Pair with mature GCC for full C++23.
- libc++ (LLVM) — Apple default, Android default, faster
std::stringSBO (22 chars vs libstdc++‘s 15), often first with new C++ features. Migrating to libc++ is common for compile-time and binary-size wins. - MS STL (Microsoft) — Open-source since 2019 (github.com/microsoft/STL), full C++23 in VS 17.10+, debug iterators by default in Debug builds.
- NVIDIA libcudacxx — heterogeneous standard library; same code on CPU and GPU.
- EASTL (EA), Folly (Meta), Abseil (Google) — production-tested replacements for std types where defaults are too slow or feature-thin.
folly::F14FastMapis 1.5-2x faster thanstd::unordered_map.
7. Idioms & style
- Naming: no single convention — Google uses
snake_casefor vars,CamelCasefor types; LLVM usesCamelCasefor types andcamelBackfor methods; std uses allsnake_case. Pick one andclang-formatit. - Formatter: clang-format (Google/LLVM/Microsoft/Mozilla/Chromium/WebKit styles built in; custom
.clang-formatfor project). Linter: clang-tidy (modernize-, bugprone-, performance-, readability-, cert-, cppcoreguidelines-, hicpp-*).include-what-you-usefor include hygiene. - Idiomatic patterns: RAII for everything (lock guards, file handles, allocations); rule of zero/three/five; pass by value-and-move;
const-correctness; preferenum class; preferstd::array/std::spanover C arrays;std::unique_ptrovernew;autofor verbose type names; AAA (Almost Always Auto, Herb Sutter); CRTP / type erasure /std::variantovervoid*; value semantics over reference semantics where possible; small-buffer optimization (small_vector,inline_vector) for hot paths. - Reviewers look for: ownership semantics (raw pointers in API surface are smell), lifetime issues (dangling refs, iterators invalidated mid-loop),
noexceptcorrectness (esp. for move ctors), value-category mistakes (move fromconst, dangling rvalue refs), thread-safety annotations (Clang’s[[clang::guarded_by]]), allocator awareness in hot paths, missing[[nodiscard]], exception safety levels (basic / strong / nothrow). - Modern guideline references: C++ Core Guidelines (Stroustrup + Sutter, isocpp.github.io), Google C++ Style Guide, LLVM Coding Standards, Mozilla C++ Portability Guide, Microsoft C++ Coding Standards. GSL (Guidelines Support Library) provides
gsl::span,gsl::not_null,gsl::Expects/Ensures.
8. Ecosystem
- Build systems: CMake 3.30+ (target-based modern style, presets, FetchContent, FILE_SET CXX_MODULES), Meson (Python-config, fast, Mesa+systemd use it), Bazel (Google, hermetic, monorepo-scale), xmake (Lua-config, batteries-included), premake (Lua → other generators), Ninja as the canonical low-level build runner.
- Package managers: Conan 2.x (JFrog, Python-config, supports binary cache via Artifactory/CCI), vcpkg (Microsoft, manifest mode + classic mode, 2400+ ports), CPM.cmake (CMake-only, FetchContent wrapper), Hunter (legacy), build2 (full system: build + dep manager).
- GUI: Qt 6.x (LGPL/commercial, dominant cross-platform), wxWidgets, Dear ImGui (immediate-mode, ubiquitous in tools/games), JUCE (audio + plugins), GTKmm, Slint (Rust-backed, embedded-friendly), FLTK (tiny), Sciter (HTML/CSS UI in native).
- Game engines: Unreal Engine 5 (Epic), CRYENGINE, Godot (core in C++; scripting in GDScript/C#), O3DE (Linux Foundation, ex-Lumberyard), Bevy (Rust, not C++ but adjacent).
- HPC/scientific: Eigen (linear algebra header-only), Armadillo, Boost, Kokkos (Sandia, performance-portable parallelism), RAJA (LLNL), OpenMP 5.x, MPI (OpenMPI, MPICH, Intel MPI), CUDA, HIP (AMD), SYCL (Khronos, Intel oneAPI, AdaptiveCpp/hipSYCL), TBB, HPX (asynchronous parallel runtime).
- ML/inference: PyTorch C++ frontend (LibTorch), TensorFlow C++ API, ONNX Runtime, TensorRT, llama.cpp (Georgi Gerganov — runs LLMs on CPU/GPU/Metal with GGUF quantization, huge influence), whisper.cpp, MLX (Apple, Metal/M-series).
- Web/network: Drogon (async, fast), Crow (Flask-like), cpp-httplib (single-header), Boost.Beast (Asio-based HTTP/WebSocket), Boost.Asio + standalone Asio, gRPC, uWebSockets (very fast), userver (Yandex async framework), restinio.
- Serialization: Protocol Buffers, Cap’n Proto, FlatBuffers (Google), MessagePack, nlohmann/json (header-only), simdjson (Daniel Lemire, multi-GB/s parser), glaze (compile-time JSON), boost::serialization.
- Testing: GoogleTest (most common), Catch2 v3 (header + cpp now), doctest (single-header, fast compile), Boost.Test, ut (boost::ut, single-header C++20), snitch (no-exception, embedded-friendly), Lest. Property-based: rapidcheck. Mocking: GMock, trompeloeil.
- Doc tools: Doxygen, Sphinx + Breathe + Exhale, Standardese, mkdocs + Doxygen, hdoc.
- Logging: spdlog (header/static, ubiquitous, sub-μs format), Boost.Log, glog (Google), quill (low-latency, async).
- Where it’s used: browsers (Chromium, Firefox, WebKit), databases (PostgreSQL extensions, MongoDB, MySQL, ClickHouse, DuckDB, RocksDB, Cassandra C++ driver), Adobe/Autodesk creative apps (Photoshop, AutoCAD, Maya), financial trading systems (Jane Street has OCaml, but most HFT is C++), embedded firmware (cars, planes, medical), Microsoft Office, all major game engines, LLVM itself, V8 / SpiderMonkey / JSC, Unreal/Unity native code, parts of Windows / macOS / iOS / Android frameworks, Linux kernel adjacent code (kernel proper is C95, but userspace tools and kernel modules use C++).
9. Gotchas
- Undefined behavior is everywhere: signed-integer overflow, OOB array access, dereferencing null/invalid pointers, use-after-free, uninitialized reads, strict-aliasing violations, double-frees, unsynchronized data races. UBSan + ASan + TSan are not optional in serious code.
- Most vexing parse:
Widget w();declares a function, not a default-constructedWidget. UseWidget w{};orauto w = Widget{};. - Initializer-list constructor preference:
std::vector<int> v{3, 0};is{3, 0}(size 2), not “3 zeros.” Usestd::vector<int> v(3, 0). - Object slicing: copying a derived into a base by value drops the derived parts. Pass polymorphic types by reference / smart pointer.
- Returning references to locals / dangling iterators after container reallocation.
auto& back = v.back(); v.push_back(x); use(back);is UB ifpush_backreallocated. std::vector<bool>is not a container ofbool(proxy refs). Usestd::vector<char>orboost::dynamic_bitsetif you need real bools.- Implicit narrowing conversions in non-brace-init contexts.
int x = 1.5;silently truncates;int x{1.5};errors. - ABI fragility:
std::stringSBO sizes differ across libstdc++ vs libc++; mixing across libraries causes corruption. Standard libraries are not ABI-compatible across major versions either. - Headers vs modules ordering: macros leak in headers; module imports do not. Mixing requires explicit
#includebefore anyimport. - Move-from objects are still destructible but in unspecified state; don’t reuse without reassigning.
- Template error messages without concepts can be 200 lines; use concepts and
static_assert. std::shared_ptrcycles leak. Break withstd::weak_ptr.auto&&is universal reference, not rvalue reference. Infor (auto&& x : range)it preserves value category — usually what you want.- Implicit
boolconversions fromint/void*can lead to surprising overload resolution. - Captures in lambdas:
[=]captures by value (incl.*thisas pointer copy in pre-C++17;[=, *this]for value copy in C++17+),[&]by reference (dangling risk). Be explicit. std::optional<T&>is not in the standard (rejected). UseT*orstd::reference_wrapper<T>.- NRVO vs copy elision rules changed in C++17 (guaranteed copy elision for prvalues) — pre-C++17 code may have surprises.
- C++20 modules +
inlinefunctions — visibility rules differ subtly from headers; some libraries shipping with both header and module interfaces have ABI gotchas. std::regexis slow — 5-100x slower than RE2, ctre, Hyperscan. Prefer alternatives for hot paths.#include <iostream>is fat — pulls thousands of LOC. Use<print>(C++23) or forward declares.
Compile-time landscape (2026)
C++ compilation is famously slow. Modern strategies:
- Precompiled headers (PCH) — 2-5x speedups on header-heavy code.
- Modules — eliminate redundant parsing across TUs. CMake 3.28+ + Ninja 1.11+ scanning is mandatory.
- Unity / jumbo builds — concatenate
.cppfiles; reduces re-parsing but breaks anonymous namespaces. Common in Chromium, UE. include-what-you-use(IWYU) — minimize transitive includes.#pragma once— universally supported now, faster than include guards on some compilers.- Forward declarations + pimpl idiom — break compile-time deps.
- ccache / sccache — content-addressed compile cache; remote backend lets a team share a build cache.
- distcc / icecream / Goma / Bazel remote — distributed compilation farms.
Interop with other languages
C++ is the universal lingua franca of native FFI. Common bidirectional paths:
| Other | Tool | Direction | Notes |
|---|---|---|---|
| C | extern "C" | both | Direct; mangle/unmangle aware |
| Rust | cxx (David Tolnay) | both, safe | Used by Mozilla (Servo), Google (Chromium), Linux kernel R4L |
| Rust | autocxx (Google) | C++ → Rust | Generates Rust bindings from C++ headers |
| Rust | bindgen | C/C++ → Rust | Lower-level, less safety |
| Rust | cbindgen | Rust → C/C++ | Header generation |
| Python | pybind11 | both | Header-only, mature, standard for C++ Python ext |
| Python | nanobind (Wenzel Jakob) | both | 4x smaller bindings, 6x faster compiles |
| Python | cppyy | C++ → Python | JIT bindings via Cling |
| Java/JVM | JNI + Project Panama FFM | both | FFM (JDK 22+) replaces JNI |
| JavaScript/Node | node-addon-api | both | N-API stable ABI |
| Go | cgo | both | Costly border crossing |
| Swift | C++ interop (Xcode 15+) | both | First-class as of 2023 |
| WASM | emscripten, Cheerp | C++ → WASM | Production-grade |
| .NET / C# | C++/CLI, P/Invoke, CppSharp | both | C++/CLI Windows-only |
Carbon
Carbon (Google, public 2022) is positioned as a “successor language” with bidirectional C++ interop, modern syntax (no preprocessor, generics with constraints, explicit pointers, no UB by default in safe mode). Still pre-1.0 in 2026 — not production-ready, but worth tracking as the heir-apparent if it ships. Compare with Herb Sutter’s cppfront / cpp2 (also experimental “10x simpler C++”) and Sean Baxter’s Circle (C++ extension with reflection + safety).
CMake modern target-based style
Modern CMake (post-3.15) is target-centric: each library declares its own usage requirements, consumers pick them up automatically via target_link_libraries.
cmake_minimum_required(VERSION 3.30)
project(myproj CXX)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # for clangd
add_library(core)
target_sources(core
PRIVATE src/core/foo.cpp src/core/bar.cpp
PUBLIC FILE_SET HEADERS BASE_DIRS include FILES include/core/foo.hpp include/core/bar.hpp
PUBLIC FILE_SET CXX_MODULES FILES src/core/utils.cppm # C++20 module
)
target_include_directories(core PUBLIC include)
target_compile_features(core PUBLIC cxx_std_23)
target_compile_options(core PRIVATE
$<$<CXX_COMPILER_ID:GNU,Clang>:-Wall -Wextra -Wpedantic>
$<$<CXX_COMPILER_ID:MSVC>:/W4>
)
# Find third-party with vcpkg or Conan
find_package(fmt CONFIG REQUIRED)
target_link_libraries(core PUBLIC fmt::fmt)
add_executable(app src/main.cpp)
target_link_libraries(app PRIVATE core)
# Testing
enable_testing()
add_subdirectory(tests)CMakePresets.json (3.19+) shares dev configurations across IDEs/CI:
{
"version": 6,
"configurePresets": [
{
"name": "default",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" }
}
]
}Modern best practices (Core Guidelines distilled)
The C++ Core Guidelines (Stroustrup + Sutter) and the C++ Core Guidelines Support Library (GSL) condense decades of experience. Highlights every modern C++ codebase should follow:
- R.20 — Use unique_ptr or shared_ptr to represent ownership. Raw pointers are non-owning observers.
- F.16 — Take rvalue references where you’ll sink.
void push(T&& x) { storage_.push_back(std::move(x)); }. - C.21 — Rule of Zero. Don’t write copy/move/destroy unless you must. Let the compiler generate them.
- CP.51 — Use
std::jthreadoverstd::thread. Automatic join + stop_token. - ES.20 — Always initialize. Default-initialized primitives are UB on read.
- SL.con.1 — Prefer
std::vectorover arrays. Usestd::arrayfor fixed-size stack storage. - Per.4 — Don’t optimize prematurely. Measure. PGO usually beats hand-tuning.
- Per.11 — Move computation from runtime to compile time.
constexpreverything that doesn’t depend on input. - NL.16 — Use a conventional class member declaration order. public → protected → private; types → constructors → destructor → methods → data.
Real-world allocator + container performance (2024 microbenchmarks)
On a typical x86_64 modern CPU (Zen 4 / Sapphire Rapids):
std::unordered_map(libstdc++): ~75 ns lookup, 40 ns insert.absl::flat_hash_map: ~25 ns lookup, ~30 ns insert — 3x faster typical wins from open addressing + SIMD probing.folly::F14FastMap: ~30 ns lookup, comparable insert.std::map(RB-tree): ~250 ns lookup — only competitive if you need ordering.boost::container::flat_map(sorted vector): ~40 ns lookup for <100 elements, cache-friendly.std::vector::push_backwith reserve: ~3 ns; without: ~6 ns amortized.std::stringSBO (libc++ 22-char limit, libstdc++ 15-char limit): zero allocation for short strings.
Use this as a sanity check, not a substitute for measuring your workload with Google Benchmark or nanobench.
Real-world C++ in 2026 — language usage observations
- Most “modern C++” production code targets C++17 or C++20. C++23 adoption is gated by toolchain support (GCC 14+, Clang 16+, MSVC 19.30+).
- Modules are real but ecosystem-thin — Boost, Qt, libfmt shipping module interfaces gradually. Most code still uses
#include. - Concepts (C++20) are widely adopted — readable template errors are too valuable to skip.
- Coroutines (C++20) have stabilized via cppcoro / folly::coro / Asio integration; everyday usage still niche.
- Embedded / freestanding code (kernel, firmware) still often C++17 with
-fno-exceptions -fno-rtti. - Compile-time string parsing (ctre, Frozen) and reflection-via-TMP (boost::pfr, magic_enum) are common workarounds while waiting for C++26 reflection.
Coroutine and ranges examples (C++20+)
Coroutines and ranges are the two biggest C++20 features that change how everyday code looks.
#include <ranges>
#include <vector>
#include <print>
int main() {
std::vector<int> nums{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// Ranges pipeline: lazy view composition
auto result = nums
| std::views::filter([](int n) { return n % 2 == 0; })
| std::views::transform([](int n) { return n * n; })
| std::ranges::to<std::vector>(); // C++23
for (int x : result) std::print("{} ", x); // 4 16 36 64 100
}#include <coroutine>
#include <generator> // C++23
#include <print>
std::generator<int> fibs() {
int a = 0, b = 1;
while (true) {
co_yield a;
std::tie(a, b) = std::pair{b, a + b};
}
}
int main() {
int i = 0;
for (int n : fibs()) {
if (i++ == 10) break;
std::print("{} ", n); // 0 1 1 2 3 5 8 13 21 34
}
}std::expected<T, E> (C++23) provides a Rust-Result-like value-or-error:
#include <expected>
#include <string>
std::expected<int, std::string> parse(std::string_view s) {
int n;
auto [p, ec] = std::from_chars(s.data(), s.data() + s.size(), n);
if (ec != std::errc{}) return std::unexpected("parse failed");
return n;
}
auto result = parse("42")
.and_then([](int n) -> std::expected<int, std::string> { return n * 2; })
.transform([](int n) { return n + 1; }); // monadic chainingC++26 preview (publication 2026)
The C++26 working draft is feature-complete around mid-2025, ISO publication 2026. Headline features:
- Static reflection (P2996) —
^^Treflection operator,[: e :]splice. Replaces most macro / TMP codegen. - Pattern matching (P2688) —
inspectexpression with structural matching, à la Rustmatch. std::execution(P2300) — sender/receiver async composition. Subsumes futures + channels + coroutines into a unified model. Major libraries (NVIDIA stdexec, libunifex) shipping reference implementations.- Contracts (P2900) —
pre,post,contract_assertfor design-by-contract; runtime-checked or build-time-erased. std::hazard_pointer,std::rcu(P2530, P2545) — lock-free reclamation for concurrent data structures.std::simd(P1928) — portable SIMD types (parallel to Vector API in Java).- Linear algebra (P1673) — BLAS-style operations on
mdspan. - Networking (proposed for C++26 or 29 — historically slipped) —
std::net::ip::tcp, async via senders. constexprcast fromvoid*(P2738), moreconstexpreverything.- Profiles + Safety profiles (Stroustrup P3081) — opt-in subsets of C++ that disallow UB-prone constructs (pointer arithmetic, casts, etc.) for safer code paths.
The safety profiles work is C++‘s answer to the regulatory and industry pressure (CISA, NSA, White House memos) recommending memory-safe languages. Whether profiles are sufficient or whether Carbon / Rust supplants C++ in greenfield systems work is the open debate of the decade.
Concurrency examples (C++20+)
#include <thread>
#include <mutex>
#include <atomic>
#include <latch>
#include <barrier>
#include <semaphore>
#include <print>
// std::jthread auto-joins on destruction + supports cooperative cancellation
void worker(std::stop_token stoken, int id) {
while (!stoken.stop_requested()) {
std::print("worker {} alive\n", id);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
int main() {
std::jthread t1{worker, 1};
std::jthread t2{worker, 2};
std::this_thread::sleep_for(std::chrono::seconds(1));
// t1.request_stop() called by destructor; auto-joined
}
// std::latch — one-shot countdown
std::latch ready{4};
auto fn = [&] { ready.count_down(); };
// ... 4 threads call fn ...
ready.wait(); // blocks until count hits 0
// std::barrier — reusable, with optional completion fn
std::barrier sync_point(3, [] { std::print("phase done\n"); });
// std::counting_semaphore — bound concurrency
std::counting_semaphore<8> slots{8};
auto run_job = [&] {
slots.acquire();
do_work();
slots.release();
};
// Atomics with explicit memory order
std::atomic<int> counter{0};
counter.fetch_add(1, std::memory_order_relaxed); // for counters
counter.store(0, std::memory_order_release); // pairs with...
auto v = counter.load(std::memory_order_acquire); // ...thisCoroutines + Asio is the modern async I/O recipe; awaitables on sockets compose cleanly:
asio::awaitable<void> echo(asio::ip::tcp::socket sock) {
char data[1024];
try {
for (;;) {
auto n = co_await sock.async_read_some(asio::buffer(data), asio::use_awaitable);
co_await asio::async_write(sock, asio::buffer(data, n), asio::use_awaitable);
}
} catch (std::exception&) { /* client closed */ }
}Sanitizer matrix (when to use what)
| Sanitizer | Catches | Overhead | When |
|---|---|---|---|
| AddressSanitizer (ASan) | Use-after-free, OOB, double-free, leaks | 2-3x runtime, 2-3x memory | All test runs, dev builds |
| UndefinedBehaviorSanitizer (UBSan) | Signed overflow, alignment, null deref, invalid casts | ~10% | All test runs |
| ThreadSanitizer (TSan) | Data races | 5-15x, 5-10x memory | Concurrency tests |
| MemorySanitizer (MSan) | Uninitialized reads | 3x | Requires recompiling all libs incl. libc++ |
| LeakSanitizer (LSan) | Memory leaks at exit | minimal | Bundled with ASan by default |
| HWAddressSanitizer (HWASan) | Like ASan but lower memory (AArch64) | 2x runtime, 1.1x memory | Production fuzzing on ARM |
| DataFlowSanitizer (DFSan) | Taint tracking | high | Security analysis |
| CFI (Control Flow Integrity) | Indirect-call type confusion | ~5% | Hardened production builds (Chromium, Android) |
CI typically runs ASan + UBSan on every PR, TSan on a subset, MSan rarely. Production builds use CFI + stack protectors.
C++20 modules — complete working example
The fragmented world of #include is finally addressable. A full minimal project demonstrating module interface unit + module partition + named module + import std:
math.cppm (module interface unit — declares the math module):
// math.cppm
export module math;
export import :geometry; // re-export a partition
import std; // C++23 std module
export namespace math {
constexpr double square(double x) { return x * x; }
export double sum(std::span<const double> xs) {
double s = 0;
for (auto x : xs) s += x;
return s;
}
}math-geometry.cppm (module partition — internal to math):
// math-geometry.cppm
export module math:geometry;
import std;
export namespace math {
struct Point { double x, y; };
export double distance(Point a, Point b) {
return std::hypot(a.x - b.x, a.y - b.y);
}
}main.cpp (consumer):
import std;
import math;
int main() {
std::vector v{1.0, 2.0, 3.0};
std::println("sum = {}", math::sum(v));
std::println("dist = {}", math::distance({0,0}, {3,4}));
}CMakeLists.txt (CMake 3.30+ with FILE_SET CXX_MODULES):
cmake_minimum_required(VERSION 3.30)
project(modules_demo CXX)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_SCAN_FOR_MODULES ON) # P1689 module dependency scan
add_library(math)
target_sources(math
PUBLIC FILE_SET CXX_MODULES FILES math.cppm math-geometry.cppm
)
target_compile_features(math PUBLIC cxx_std_23)
add_executable(app main.cpp)
target_link_libraries(app PRIVATE math)Compiler flags by vendor (2026 reality):
- Clang 19+:
-std=c++23 -fmodules -fbuiltin-module-map. BMI files emitted as.pcm. Production-ready as of 18+. - GCC 14+:
-std=c++23 -fmodules-ts(legacy spelling) /-fmodules(15+). BMI as.gcm. Partial — module partitions stabilizing in 15. - MSVC 19.30+ (VS 2022 17.x):
/std:c++latest /experimental:module(early) →/std:c++20 /module(modern). BMI as.ifc. Production-ready in 17.4+. - Ninja 1.11+ required for the dynamic dependency protocol (P1689 / JSON
provides/requires).
Header units bridge legacy #include into the module world:
import <vector>; // header unit — translated to BMI, faster than #include
import <string>;These produce per-header BMIs but don’t isolate macros — they’re a migration bridge, not the destination.
Real-world cross-language interop
C++ is the lingua franca of native FFI. The 2024-26 toolchain has stabilized around a few clear winners per language:
C++ ↔ Rust (cxx + autocxx) — type-safe, bidirectional, used in Chromium, Servo, R4L:
// build.rs uses cxx-build
#[cxx::bridge]
mod ffi {
extern "Rust" {
fn rust_compute(x: i32) -> i32;
}
unsafe extern "C++" {
include!("myapp/cpp_lib.h");
fn cpp_render(data: &CxxString) -> i32;
}
}
fn rust_compute(x: i32) -> i32 { x * 2 }autocxx (Google) auto-generates the bridge from C++ headers via libclang; the dev workflow is #include "header.h" then include_cpp! { #include "header.h" generate!("MyClass") }. Production at Google for Chromium UI components, Firefox’s stylo CSS engine. libloading covers the dlopen/LoadLibrary case when you don’t have headers.
C++ ↔ Python (pybind11, nanobind, Cython, cffi):
| Tool | Style | Binary size | Compile time | When |
|---|---|---|---|---|
| pybind11 | Header-only, declarative | baseline | baseline | Mature C++ Python bindings; PyTorch, OpenCV, Pinocchio use it |
| nanobind | Header-only, ABI-stable Python (3.8+) | 4x smaller | 6x faster | New projects; Wenzel Jakob (same author as pybind11) |
| Cython | .pyx Python-superset compiled to C | medium | slow (full C compile) | numpy, scikit-learn, sage; when you control both sides |
| cffi | Runtime C ABI binding | small | none | Pure-C libs, when you don’t want a build dep |
| cppyy | JIT via Cling (LLVM) | runtime cost | none | Interactive / data science (CERN ROOT) |
Minimal pybind11 + nanobind comparison:
// pybind11
#include <pybind11/pybind11.h>
PYBIND11_MODULE(mymod, m) {
m.def("add", [](int a, int b) { return a + b; });
}
// nanobind — visually identical, 4x smaller .so, 6x faster compile
#include <nanobind/nanobind.h>
NB_MODULE(mymod, m) {
m.def("add", [](int a, int b) { return a + b; });
}Build both with scikit-build-core or meson-python + pyproject.toml.
C++ ↔ WebAssembly (emscripten, Cheerp):
- emscripten — the dominant choice; LLVM-based, includes wasm-ld, Asyncify for sync APIs over async JS, file-system emulation (
MEMFS,IDBFS,NODEFS). Use cases: AutoCAD Web, Figma rendering engine, Photoshop Web, Google Earth, Unity WebGL builds, Unreal HTML5.
em++ -std=c++23 -O2 -sWASM=1 -sEXPORTED_FUNCTIONS='["_main","_compute"]' \
-sMODULARIZE=1 -sEXPORT_ES6=1 main.cpp -o main.mjs- Cheerp — alternative LLVM-based, dual-target (compile parts to JS, parts to WASM, share types). Used at Leaning Technologies (CheerpJ for Java→WASM, CheerpX for x86→WASM, including running entire Windows binaries in browser).
WASI Preview 2 + Component Model (wasi-sdk + wit-bindgen) is the path to portable C++ components running on Wasmtime, Spin, Fastly Compute@Edge, Cloudflare workerd, WasmEdge.
10. Citations
- cppreference (C++ language + library): https://en.cppreference.com/w/cpp
- isocpp.org Standard Status (C++23 published, C++26 WIP): https://isocpp.org/std/status
- C++23 / ISO/IEC 14882:2024 overview, deducing this, std::expected, std::print, std::flat_map, mdspan, std::generator: https://en.wikipedia.org/wiki/C%2B%2B23
- Compiler Explorer (godbolt): https://godbolt.org/
- CMake docs: https://cmake.org/documentation/
- clang-format / clang-tidy: https://clang.llvm.org/docs/ClangFormat.html ; https://clang.llvm.org/extra/clang-tidy/
- LLVM coding standard: https://llvm.org/docs/CodingStandards.html
- Google C++ Style Guide: https://google.github.io/styleguide/cppguide.html
- C++ Core Guidelines (Stroustrup/Sutter): https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines