Modernes C++
Leitfaden zum Schreiben von modernem C++ unter Verwendung der Idiome C++20, C++23 und C++26. Konzentriert sich auf Muster, die Schwachstellenklassen eliminieren und Boilerplate reduzieren, mit einem Sicherheitsschwerpunkt von Trail of Bits.
Wann Sie Diese Skill Verwenden Sollten
- Schreiben neuer C++-Funktionen, -Klassen oder -Bibliotheken
- Modernisieren vorhandenen C++-Codes (Muster vor C++20)
- Auswählen zwischen Legacy- und modernen Ansätzen
- Arbeiten an sicherheitskritischem oder sicherheitsrelevantem C++
- Überprüfen von C++-Code auf die Verwendung moderner Idiome
Wann Sie Diese Skill NICHT Verwenden Sollten
- Benutzer fordert ausdrücklich älteren Standard: Respektieren Sie Einschränkungen (eingebettetes System, Legacy-ABI)
- Reiner C-Code: Diese Skill ist C++-spezifisch
- Build-System-Fragen: CMake-, Meson-, Bazel-Konfiguration ist nicht abgedeckt
- Nicht-C++-Projekte: Gemischte Codebasen, in denen C++ nicht primär ist
Anti-Patterns, die Sie Vermeiden Sollten
| Vermeiden | Stattdessen Verwenden | Warum |
|---|---|---|
new/delete | std::make_unique, std::make_shared | Beseitigt Lecks, Double-Free |
| Rohe besitzende Zeiger | std::unique_ptr, std::shared_ptr | RAII-Besitzsemantik |
C-Arrays (int arr[N]) | std::array<int, N> | Grenzbewusst, Wertesemantik |
| Zeiger+Länge-Parameter | std::span<T> | Nicht-besitzend, grenzprüfbar |
printf / sprintf | std::format, std::print | Typsicher, kein Pufferüberlauf |
C-Style-Casts (int)x | static_cast<int>(x) | Explizite Absicht, prüfbar |
#define-Konstanten | constexpr-Variablen | Bereichsgebunden, typisiert, debuggbar |
SFINAE / enable_if | Konzepte + requires | Lesbare Constraints und Fehler |
| Fehlercodes + Ausgabeparameter | std::expected<T, E> | Kombinierbar, typsichere Fehler |
union | std::variant | Typsicher, kein stilles UB |
Rohes mutex.lock()/unlock() | std::scoped_lock | Ausnahmesicher, keine Deadlocks |
std::thread | std::jthread | Automatisches Join, Stop-Token-Unterstützung |
assert()-Makro | contract_assert (C++26) | Für Werkzeuge sichtbar, konfigurierbar |
| Manuelles CRTP | Herleitendes this (C++23) | Einfacher, keine Template-Boilerplate |
| Makro-Codegenerierung | Reflection (C++26) | Null-Overhead, kombinierbar |
Siehe anti-patterns.md für die vollständige Tabelle (30+ Muster).
Entscheidungsbaum
Was tun Sie?
|
+-- Neuen C++-Code schreiben?
| +-- Standardmäßig moderne Idiome verwenden (C++20/23)
| +-- Den neuesten Standard wählen, den Ihr Compiler unterstützt
| +-- Siehe Feature-Stufen unten
|
+-- Vorhandenen Code modernisieren?
| +-- Mit Ersetzungen der Stufe 1 (C++20/23) beginnen
| +-- Nach Sicherheitsauswirkungen priorisieren (Speicher > Typen > Stil)
| +-- Siehe anti-patterns.md für die Migrationstabelle
|
+-- Sicherheitskritischer Code?
| +-- Compiler-Härtungsflags aktivieren (siehe unten)
| +-- Gehärteten libc++-Modus aktivieren
| +-- Sanitizer in CI ausführen
| +-- Siehe safe-idioms.md und compiler-hardening.md
|
+-- C++26-Features verwenden?
+-- Reflection: JA, planen Sie dafür (GCC 16+)
+-- Contracts: vorsichtig, für neue API-Grenzen
+-- std::execution: warten Sie auf die Reife des Ökosystems
+-- Siehe cpp26-features.md
Feature-Stufen
Features werden nach praktischer Verwendbarkeit heute geordnet, nicht nach Standardversion.
Stufe 1: Heute Verwenden (C++20/23, solide Compiler-Unterstützung)
| Feature | Ersetzt | Standard |
|---|---|---|
Konzepte + requires | SFINAE, enable_if | C++20 |
| Ranges + Views | Rohe Iterator-Schleifen | C++20 |
std::span<T> | Zeiger + Länge | C++20 |
std::format | sprintf, iostream-Ketten | C++20 |
Drei-Wege-Vergleich <=> | Manuelle Vergleichsoperatoren | C++20 |
std::jthread | std::thread + manuelles Join | C++20 |
| Designierte Initialisierer | Positionelle Struct-Init | C++20 |
std::expected<T,E> | Fehlercodes, Ausnahmen an Grenzen | C++23 |
std::print / std::println | printf, std::cout << | C++23 |
Herleitendes this | CRTP, const/non-const-Duplizierung | C++23 |
std::flat_map | std::map für leseintensive Nutzung | C++23 |
Monadisches std::optional | Verschachtelte if-Prüfungen auf Optionals | C++23 |
Siehe cpp20-features.md und cpp23-features.md.
Stufe 2: Jetzt Bereitstellen (kein Standard-Bump nötig)
Diese verbessern die Sicherheit, ohne Ihre C++-Standardversion zu ändern:
- Compiler-Härtungsflags –
-D_FORTIFY_SOURCE=3,-fstack-protector-strong,-ftrivial-auto-var-init=zero - Gehärtetes libc++ –
-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FASTfür ~0,3% Overhead bei Grenzprüfungen - Sanitizer in CI – ASan + UBSan als Minimum; TSan für nebenläufigen Code
- Warnflags –
-Wall -Wextra -Wpedantic -Werror
Siehe compiler-hardening.md.
Stufe 3: Planen (C++26, die Umstrukturierung lohnt sich)
Reflection ist das mit Abstand transformativste C++26-Feature. Es eliminiert:
- Serialisierungs-Boilerplate (eine generische Funktion ersetzt pro-Struct
to_json) - Code-Generatoren (protobuf-Codegen, Qt MOC)
- Makrobasierte Registrierung und Enum-zu-String-Hacks
GCC 16 (April 2026) hat Reflection gemerged. Planen Sie neuen Code, um davon zu profitieren.
Stufe 4: Beobachten (C++26, braucht Reifung)
- Contracts (
pre/post/contract_assert) – Besser alsassert(), aber keine Unterstützung für virtuelle Funktionen und begrenzte Compiler-Unterstützung. Für neue API-Grenzen vorsichtig einführen. - std::execution (Senders/Receiver) – Leistungsstarkes asynchrones Framework, aber steile Lernkurve, kein mitgelieferter Scheduler und schlechte Dokumentation. Warten Sie auf die Reife des Ökosystems.
Siehe cpp26-features.md.
Compiler-Härtung Kurzreferenz
Essentielle 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-Spezifisch
-Wunsafe-buffer-usage
Gehärtetes libc++ (nur Clang/libc++)
-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST
Google hat dies in Chrome und seinem Server-Fleet eingesetzt: ~0,3% Overhead, 1000+ gefundene Fehler, 30% weniger Produktions-Segfaults.
Siehe compiler-hardening.md für die vollständige Anleitung.
Rationalisierungen, die Sie Zurückweisen Sollten
| Rationalisierung | Warum sie falsch ist |
|---|---|
| "Es compiliert ohne Warnungen" | Warnungen hängen von den aktivierten Flags ab. Fügen Sie -Wall -Wextra -Wpedantic hinzu. |
| "ASan ist zu langsam für die Produktion" | Verwenden Sie GWP-ASan für samplingbasierte Produktionserkennung (~0% Overhead). |
| "Wir verwenden nur sichere Container" | Iterator-Invalidierung und ungeprüfter optional-Zugriff sind immer noch ausnutzbar. |
| "Intelligente Zeiger sind langsamer" | std::unique_ptr hat Null-Overhead im Vergleich zu rohen Zeigern. Messen Sie, bevor Sie behaupten. |
| "Unser Code hat keine Speicherfehler" | Google fand 1000+ Fehler, als es gehärtetes libc++ aktivierte. Das taten auch alle anderen. |
| "C++26-Features sind noch nicht verfügbar" | C++20/23-Features sind es. Härtungsflags funktionieren mit jedem Standard. Fangen Sie dort an. |
| "Modernes C++ ist schwerer zu lesen" | std::expected ist lesbarer als die Prüfung von Fehlercodes über 5 Ausgabeparameter hinweg. |
Checkliste für Best Practices
- Verwenden Sie intelligente Zeiger für Besitz, rohe Zeiger nur für nicht-besitzende Beobachtung
- Bevorzugen Sie
std::spangegenüber Zeiger+Länge für Funktionsparameter - Verwenden Sie
std::expectedfür Funktionen, die mit typisierten Fehlern fehlschlagen können - Beschränken Sie Templates mit Konzepten, nicht mit SFINAE
- Aktivieren Sie Compiler-Härtungsflags und gehärtetes libc++ in allen Builds
- Führen Sie ASan + UBSan in CI aus; fügen Sie TSan für nebenläufigen Code hinzu
- Verwenden Sie
constexpr/consteval, wo möglich (UB-frei per Design) - Markieren Sie Funktionen mit
[[nodiscard]], wenn das Ignorieren des Rückgabewerts wahrscheinlich ein Fehler ist - Bevorzugen Sie Wertesemantik; verwenden Sie
std::variantstattunion,enum classstattenum - Initialisieren Sie alle Variablen bei der Deklaration
Weiterlesen
- anti-patterns.md – Vollständige Legacy-zu-Modern-Migrationstabelle (30+ Muster)
- cpp20-features.md – Konzepte, Ranges, span, format, Coroutinen
- cpp23-features.md – expected, print, deducing this, flat_map
- cpp26-features.md – Reflection, Contracts, Speichersicherheitsverbesserungen
- compiler-hardening.md – Flags, Sanitizer, gehärtetes libc++
- safe-idioms.md – Sicherheitsmuster nach Schwachstellenklasse