modern-cpp について
modern-cppは、C++20、C++23、C++26のイディオムを用いたコードの作成、近代化、レビューを支援するセキュリティ重視のスキルです。安全性を高めるコーディングパターンとコンパイラ強化の指針を示し、機能を実用成熟度別に整理します。
主な機能
- 01旧来のパターンを現代的なC++イディオムに置換
- 02C++20およびC++23の言語機能を活用
- 03コンパイラ強化フラグとサニタイザーの適用
- 04安全性を考慮したC++コードのレビュー
- 05成熟度に基づくC++26機能の評価
活用シーン
- 01セキュリティが重要なC++コードの作成
- 02C++20以前のコードの近代化
- 03旧来と現代的な実装方法の選択
- 04C++イディオムの採用状況のレビュー
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ trailofbits/ skills --skill modern-cppインストール後、Claude Code で/modern-cppを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/anti-patterns.mdcompiler-hardening.mdcpp20-features.mdcpp23-features.mdcpp26-features.mdsafe-idioms.md詳細
モダン C++
C++20、C++23、C++26 のイディオムを使ってモダンな C++ を書くためのガイドです。脆弱性の種類をなくし、定型コードを減らすパターンに重点を置き、Trail of Bits のセキュリティ面での知見を取り入れています。
このスキルを使う場面
- 新しい C++ 関数、クラス、ライブラリを書く
- 既存の C++ コードをモダン化する(C++20 より前のパターン)
- レガシーな方法とモダンな方法のどちらを使うか選ぶ
- セキュリティや安全性が重要な C++ に取り組む
- モダンなイディオムの採用状況について C++ コードをレビューする
このスキルを使わない場面
- ユーザーが古い規格を明示的に要求している場合:制約(組み込み環境、レガシー ABI)を尊重してください
- 純粋な C コード:このスキルは C++ 専用です
- ビルドシステムに関する質問:CMake、Meson、Bazel の設定は対象外です
- C++ 以外のプロジェクト:C++ が主要言語ではない混在コードベース
避けるべきアンチパターン
| 避けるもの | 代わりに使うもの | 理由 |
|---|---|---|
new/delete | std::make_unique, std::make_shared | メモリーリークや二重解放を防ぎます |
| 所有権を持つ生ポインター | std::unique_ptr, std::shared_ptr | RAII による所有権管理 |
C 配列(int arr[N]) | std::array<int, N> | 境界を考慮し、値セマンティクスを提供します |
| ポインターと長さのパラメーター | std::span<T> | 非所有で、境界をチェックできます |
printf / sprintf | std::format, std::print | 型安全で、バッファーオーバーフローがありません |
C スタイルのキャスト (int)x | static_cast<int>(x) | 意図が明確で、監査しやすくなります |
#define 定数 | constexpr 変数 | スコープがあり、型安全で、デバッグしやすくなります |
SFINAE / enable_if | Concepts + requires | 制約とエラーメッセージが読みやすくなります |
| エラーコードと出力パラメーター | std::expected<T, E> | 合成可能で、型安全なエラー処理を実現します |
union | std::variant | 型安全で、暗黙的な未定義動作がありません |
生の mutex.lock()/unlock() | std::scoped_lock | 例外安全で、デッドロックを防ぎます |
std::thread | std::jthread | 自動的に join し、停止トークンをサポートします |
assert() マクロ | contract_assert (C++26) | ツールから認識でき、設定可能です |
| 手動の CRTP | Deducing this (C++23) | より簡潔で、テンプレートの定型コードが不要です |
| マクロによるコード生成 | Reflection (C++26) | オーバーヘッドがなく、合成可能です |
全項目(30 以上のパターン)については、anti-patterns.md を参照してください。
判断フローチャート
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
機能のティア
機能は規格のバージョンではなく、現在の実用性に基づいてランク付けされています。
ティア 1:今すぐ使う(C++20/23、コンパイラーのサポートが充実)
| 機能 | 置き換えるもの | 規格 |
|---|---|---|
Concepts + requires | SFINAE、enable_if | C++20 |
| Ranges + views | 生のイテレーターによるループ | C++20 |
std::span<T> | ポインターと長さ | C++20 |
std::format | sprintf、iostream の連結 | C++20 |
三方比較 <=> | 手動の比較演算子 | C++20 |
std::jthread | std::thread + 手動の join | C++20 |
| 指定イニシャライザー | 位置ベースの構造体初期化 | C++20 |
std::expected<T,E> | エラーコード、境界での例外 | C++23 |
std::print / std::println | printf、std::cout << | C++23 |
Deducing this | CRTP、const/非 const の重複 | C++23 |
std::flat_map | 読み取り中心の用途での std::map | C++23 |
モナディックな std::optional | optional に対するネストした if チェック | C++23 |
cpp20-features.md と cpp23-features.md を参照してください。
ティア 2:今すぐ導入する(規格の更新は不要)
C++ の規格バージョンを変更せずに、安全性を向上できます。
- コンパイラーの強化フラグ —
-D_FORTIFY_SOURCE=3,-fstack-protector-strong,-ftrivial-auto-var-init=zero - 強化版 libc++ — 約 0.3% のオーバーヘッドで境界チェックを行う
-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST - CI でのサニタイザー — 最低限 ASan + UBSan、並行処理コードには TSan
- 警告フラグ —
-Wall -Wextra -Wpedantic -Werror
compiler-hardening.md を参照してください。
Tier 3:導入を計画する(C++26、構造の見直しを検討する価値があります)
Reflection は、C++26 の機能の中で最も大きな変革をもたらす機能です。次のものが不要になります。
- シリアライズの定型コード(構造体ごとの
to_jsonを、汎用関数 1 つに置き換えます) - コードジェネレーター(protobuf のコード生成、Qt MOC)
- マクロベースの登録や、列挙型から文字列への変換のハック
GCC 16(2026 年 4 月)では、Reflection がマージされています。新しいコードは、その恩恵を受けられるよう計画してください。
Tier 4:動向を注視する(C++26、成熟が必要です)
- Contracts(
pre/post/contract_assert) —assert()より優れていますが、仮想関数はサポートされておらず、コンパイラーのサポートも限定的です。新しい API の境界で慎重に導入してください。 - std::execution(送信側/受信側) — 強力な非同期フレームワークですが、学習曲線が急で、付属するスケジューラーがなく、ドキュメントも不十分です。エコシステムが成熟するまで待ってください。
cpp26-features.md を参照してください。
コンパイラーのハードニング早見表
必須フラグ(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 固有
-Wunsafe-buffer-usage
ハードニングされた libc++(Clang/libc++ のみ)
-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST
Google はこれを Chrome とサーバーフリート全体に導入しました。オーバーヘッドは約 0.3%で、1000 件を超えるバグが見つかり、本番環境のセグメンテーション違反が 30%減少しました。
詳しいガイドは compiler-hardening.md を参照してください。
退けるべき合理化
| 合理化 | それが誤りである理由 |
|---|---|
| 「警告なしでコンパイルできます」 | 警告は有効にするフラグによって異なります。-Wall -Wextra -Wpedantic を追加してください。 |
| 「ASan は本番環境では遅すぎます」 | サンプリングベースで本番環境の問題を検出できる GWP-ASan を使ってください(オーバーヘッドは約 0%)。 |
| 「安全なコンテナーだけを使っています」 | イテレーターの無効化や、チェックされない optional へのアクセスは、依然として悪用される可能性があります。 |
| 「スマートポインターは遅いです」 | std::unique_ptr のオーバーヘッドは、生ポインターと比べてゼロです。主張する前に測定してください。 |
| 「コードにメモリーバグはありません」 | Google はハードニングされた libc++ を有効にした際に、1000 件を超えるバグを発見しました。他の組織も同様です。 |
| 「C++26 の機能はまだ使えません」 | C++20/23 の機能は使えます。ハードニングフラグはどの標準でも機能します。まずはそこから始めてください。 |
| 「モダン C++ は読みづらいです」 | 5 つの出力引数にまたがってエラーコードを確認するより、std::expected のほうが読みやすいです。 |
ベストプラクティスのチェックリスト
- 所有権にはスマートポインターを使い、生ポインターは非所有の参照に限って使う
- 関数の引数には、ポインターと長さの組み合わせより
std::spanを優先する - 型付きエラーで失敗する可能性がある関数には
std::expectedを使う - SFINAE ではなく、コンセプトでテンプレートを制約する
- すべてのビルドでコンパイラーのハードニングフラグとハードニングされた libc++ を有効にする
- CI で ASan と UBSan を実行し、並行コードには TSan を追加する
- 可能な場合は
constexpr/constevalを使う(設計上、未定義動作がありません) - 戻り値を無視するとバグになりやすい関数には
[[nodiscard]]を付ける - 値セマンティクスを優先し、
unionの代わりにstd::variantを、enumの代わりにenum classを使う - すべての変数を宣言時に初期化する
次に読む
- anti-patterns.md — レガシーからモダンな手法への移行表の全体版(30 以上のパターン)
- cpp20-features.md — コンセプト、ranges、span、format、コルーチン
- cpp23-features.md — expected、print、deducing this、flat_map
- cpp26-features.md — Reflection、contracts、メモリー安全性の改善
- compiler-hardening.md — フラグ、サニタイザー、ハードニングされた libc++
- safe-idioms.md — 脆弱性の種類別のセキュリティパターン