Loading...
Loading...
Guides C++ code toward modern idioms (C++20/23/26). Use when writing new C++ code, modernizing legacy patterns, or working on security-critical C++. Replaces raw pointers with smart pointers, SFINAE with concepts, printf with std::print, error codes with std::expected.
npx skill4agent add trailofbits/skills modern-cpp| Avoid | Use Instead | Why |
|---|---|---|
| | Eliminates leaks, double-free |
| Raw owning pointers | | RAII ownership semantics |
C arrays ( | | Bounds-aware, value semantics |
| Pointer + length params | | Non-owning, bounds-checkable |
| | Type-safe, no buffer overflow |
C-style casts | | Explicit intent, auditable |
| | Scoped, typed, debuggable |
SFINAE / | Concepts + | Readable constraints and errors |
| Error codes + out params | | Composable, type-safe errors |
| | Type-safe, no silent UB |
Raw | | Exception-safe, no deadlocks |
| | Auto-join, stop token support |
| | Visible to tooling, configurable |
| Manual CRTP | Deducing | Simpler, no template boilerplate |
| Macro code generation | Reflection (C++26) | Zero-overhead, composable |
What are you doing?
|
+-- Writing new C++ code?
| +-- Use modern idioms by default (C++20/23)
| +-- Choose the newest standard your compiler supports
| +-- See Feature Tiers below
|
+-- Modernizing existing code?
| +-- Start with Tier 1 (C++20/23) replacements
| +-- Prioritize by security impact (memory > types > style)
| +-- See anti-patterns.md for the migration table
|
+-- Security-critical code?
| +-- Enable compiler hardening flags (see below)
| +-- Enable hardened libc++ mode
| +-- Run sanitizers in CI
| +-- See safe-idioms.md and compiler-hardening.md
|
+-- Using C++26 features?
+-- Reflection: YES, plan for it (GCC 16+)
+-- Contracts: cautiously, for new API boundaries
+-- std::execution: wait for ecosystem maturity
+-- See cpp26-features.md| Feature | Replaces | Standard |
|---|---|---|
Concepts + | SFINAE, | C++20 |
| Ranges + views | Raw iterator loops | C++20 |
| Pointer + length | C++20 |
| | C++20 |
Three-way comparison | Manual comparison operators | C++20 |
| | C++20 |
| Designated initializers | Positional struct init | C++20 |
| Error codes, exceptions at boundaries | C++23 |
| | C++23 |
Deducing | CRTP, const/non-const duplication | C++23 |
| | C++23 |
Monadic | Nested if-checks on optionals | C++23 |
-D_FORTIFY_SOURCE=3-fstack-protector-strong-ftrivial-auto-var-init=zero-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST-Wall -Wextra -Wpedantic -Werrorto_jsonprepostcontract_assertassert()-Wall -Wextra -Wpedantic -Werror
-D_FORTIFY_SOURCE=3
-fstack-protector-strong
-fstack-clash-protection
-ftrivial-auto-var-init=zero
-fPIE -pie
-Wl,-z,relro,-z,now-Wunsafe-buffer-usage-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST| Rationalization | Why It's Wrong |
|---|---|
| "It compiles without warnings" | Warnings depend on which flags you enable. Add |
| "ASan is too slow for production" | Use GWP-ASan for sampling-based production detection (~0% overhead). |
| "We only use safe containers" | Iterator invalidation and unchecked |
| "Smart pointers are slower" | |
| "Our code doesn't have memory bugs" | Google found 1000+ bugs when enabling hardened libc++. So did everyone else. |
| "C++26 features aren't available yet" | C++20/23 features are. Hardening flags work on any standard. Start there. |
| "Modern C++ is harder to read" | |
std::spanstd::expectedconstexprconsteval[[nodiscard]]std::variantunionenum classenum