Skip to content
cccskills
FreePublished on GitHub

modern-cpp

Write or modernize C++ with guidance on C++20, C++23, and C++26 features. Review memory ownership, error handling, and template constraints, with recommendations for compiler protections and runtime checks that detect bugs.

OriginalShow the original description

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.

See how to install

Good for

  • Modernize legacy C++ patterns
  • Choose approaches for new C++ code
  • Review memory ownership and error handling
  • Review compiler protections for security-sensitive code

Files included (7)

  • SKILL.md8.5 KB
  • references/anti-patterns.md5.5 KB
  • references/compiler-hardening.md7.3 KB
  • references/cpp20-features.md7.0 KB
  • references/cpp23-features.md7.0 KB
  • references/cpp26-features.md7.5 KB
  • references/safe-idioms.md8.1 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Modern C++

Guide for writing modern C++ using C++20, C++23, and C++26 idioms. Focuses on patterns that eliminate vulnerability classes and reduce boilerplate, with a security emphasis from Trail of Bits.

When to Use This Skill

  • Writing new C++ functions, classes, or libraries
  • Modernizing existing C++ code (pre-C++20 patterns)
  • Choosing between legacy and modern approaches
  • Working on security-critical or safety-sensitive C++
  • Reviewing C++ code for modern idiom adoption

When NOT to Use This Skill

  • User explicitly requires older standard: Respect constraints (embedded, legacy ABI)
  • Pure C code: This skill is C++-specific
  • Build system questions: CMake, Meson, Bazel configuration is out of scope
  • Non-C++ projects: Mixed codebases where C++ isn't primary

Anti-Patterns to Avoid

AvoidUse InsteadWhy
new/deletestd::make_unique, std::make_sharedEliminates leaks, double-free
Raw owning pointersstd::unique_ptr, std::shared_ptrRAII ownership semantics
C arrays (int arr[N])std::array<int, N>Bounds-aware, value semantics
Pointer + length paramsstd::span<T>Non-owning, bounds-checkable
printf / sprintfstd::format, std::printType-safe, no buffer overflow
C-style casts (int)xstatic_cast<int>(x)Explicit intent, auditable
#define constantsconstexpr variablesScoped, typed, debuggable
SFINAE / enable_ifConcepts + requiresReadable constraints and errors
Error codes + out paramsstd::expected<T, E>Composable, type-safe errors
unionstd::variantType-safe, no silent UB
Raw mutex.lock()/unlock()std::scoped_lockException-safe, no deadlocks
std::threadstd::jthreadAuto-join, stop token support
assert() macrocontract_assert (C++26)Visible to tooling, configurable
Manual CRTPDeducing this (C++23)Simpler, no template boilerplate
Macro code generationReflection (C++26)Zero-overhead, composable

See anti-patterns.md for the full table (30+ patterns).

Decision Tree

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 Tiers

Features are ranked by practical usability today, not by standard version.

Tier 1: Use Today (C++20/23, solid compiler support)

FeatureReplacesStandard
Concepts + requiresSFINAE, enable_ifC++20
Ranges + viewsRaw iterator loopsC++20
std::span<T>Pointer + lengthC++20
std::formatsprintf, iostream chainsC++20
Three-way comparison <=>Manual comparison operatorsC++20
std::jthreadstd::thread + manual joinC++20
Designated initializersPositional struct initC++20
std::expected<T,E>Error codes, exceptions at boundariesC++23
std::print / std::printlnprintf, std::cout <<C++23
Deducing thisCRTP, const/non-const duplicationC++23
std::flat_mapstd::map for read-heavy useC++23
Monadic std::optionalNested if-checks on optionalsC++23

See cpp20-features.md and cpp23-features.md.

Tier 2: Deploy Now (no standard bump needed)

These improve safety without changing your C++ standard version:

  • Compiler hardening flags — -D_FORTIFY_SOURCE=3, -fstack-protector-strong, -ftrivial-auto-var-init=zero
  • Hardened libc++ — -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST for ~0.3% overhead bounds-checking
  • Sanitizers in CI — ASan + UBSan as minimum; TSan for concurrent code
  • Warning flags — -Wall -Wextra -Wpedantic -Werror

See compiler-hardening.md.

Tier 3: Plan For (C++26, worth restructuring around)

Reflection is the single most transformative C++26 feature. It eliminates:

  • Serialization boilerplate (one generic function replaces per-struct to_json)
  • Code generators (protobuf codegen, Qt MOC)
  • Macro-based registration and enum-to-string hacks

GCC 16 (April 2026) has reflection merged. Plan new code to benefit from it.

Tier 4: Watch (C++26, needs maturation)

  • Contracts (pre/post/contract_assert) — Better than assert(), but no virtual function support and limited compiler support. Adopt cautiously for new API boundaries.
  • std::execution (senders/receivers) — Powerful async framework, but steep learning curve, no scheduler ships with it, and poor documentation. Wait for ecosystem maturity.

See cpp26-features.md.

Compiler Hardening Quick Reference

Essential Flags (GCC + Clang)

-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

Clang-Specific

-Wunsafe-buffer-usage

Hardened libc++ (Clang/libc++ only)

-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST

Google deployed this across Chrome and their server fleet: ~0.3% overhead, 1000+ bugs found, 30% reduction in production segfaults.

See compiler-hardening.md for the full guide.

Rationalizations to Reject

RationalizationWhy It's Wrong
"It compiles without warnings"Warnings depend on which flags you enable. Add -Wall -Wextra -Wpedantic.
"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 optional access are still exploitable.
"Smart pointers are slower"std::unique_ptr has zero overhead vs raw pointers. Measure before claiming.
"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::expected is more readable than checking error codes across 5 out-params.

Best Practices Checklist

  • Use smart pointers for ownership, raw pointers only for non-owning observation
  • Prefer std::span over pointer + length for function parameters
  • Use std::expected for functions that can fail with typed errors
  • Constrain templates with concepts, not SFINAE
  • Enable compiler hardening flags and hardened libc++ in all builds
  • Run ASan + UBSan in CI; add TSan for concurrent code
  • Use constexpr / consteval where possible (UB-free by design)
  • Mark functions [[nodiscard]] when ignoring the return value is likely a bug
  • Prefer value semantics; use std::variant over union, enum class over enum
  • Initialize all variables at declaration

Read Next

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Build and test code with AddressSanitizer, a tool that detects invalid memory access during execution. Configure checks for C/C++ and unsafe Rust, investigate crash reports, and adjust settings for fuzzing, or testing with generated inputs.

  • Detect memory errors while fuzzing C/C++
  • Test unsafe Rust and calls to external libraries
  • Interpret an ASan crash report
trailofbits/skills7.6KUpdated Oct 16, 2026

aflpp

FreeSummary

Sets up AFL++ to test C/C++ programs with varied generated inputs, a technique called fuzzing. Covers running tests across CPU cores, monitoring progress, reducing input collections, and reproducing crashes for investigation.

  • Running C/C++ fuzzing across multiple CPU cores
  • Exploring further after libFuzzer progress stalls
  • Monitoring fuzzing progress and stability
trailofbits/skills7.6KUpdated Oct 16, 2026

Audits GitHub Actions workflows that run AI coding agents. Traces how attacker-controlled content reaches prompts, checks permissions and sandbox settings, and reports evidence, severity, and fixes for prompt injection and related configuration risks.

  • Reviewing workflows that run AI coding agents
  • Tracing issue and PR content into agent prompts
  • Checking sandbox settings and user allowlists
trailofbits/skills7.6KUpdated Oct 16, 2026

Reviews Algorand smart contracts written in TEAL or PyTeal for 11 vulnerability patterns. Produces a complete coverage table and findings with code references, severity ratings, and suggested fixes, with optional automated checks using Tealer.

  • Security checks before an Algorand contract audit
  • Reviewing TEAL or PyTeal transaction validation
  • Verifying fixes for reported vulnerabilities
trailofbits/skills7.6KUpdated Oct 16, 2026

atheris

FreeSummary

Set up Atheris to test Python code and C extensions with automatically varied inputs. It guides test harness creation, coverage tracking to explore more code, and AddressSanitizer setup for finding memory errors.

  • Fuzzing a Python package or parser
  • Investigating memory corruption in Python C extensions
  • Turning raw bytes into typed test arguments
trailofbits/skills7.6KUpdated Oct 16, 2026

Connect static analysis results and human audit notes to a Trailmark code graph. Group findings by severity and compare them with input flow, impact, and privilege boundaries to prioritize investigation and understand findings in their code context.

  • Connecting Semgrep or CodeQL results to code structure
  • Combining human audit notes with automated findings
  • Prioritizing findings using input flow and impact
trailofbits/skills7.6KUpdated Oct 16, 2026

See all skills by trailofbits

Report a problem with this skill