关于 modern-cpp
modern-cpp 是一项面向安全的技能,用于编写、现代化改造和审查采用 C++20、C++23 与 C++26 惯用法的 C++ 代码。它结合更安全的编码模式与编译器加固指南,并按实际成熟度区分语言特性。
主要功能
- 01用现代 C++ 惯用法替换旧模式
- 02采用 C++20 和 C++23 语言特性
- 03应用编译器加固标志和 sanitizer
- 04审查 C++ 代码中的安全模式
- 05按成熟度评估 C++26 特性
适用场景
- 01编写安全关键的 C++ 代码
- 02现代化改造 C++20 之前的代码
- 03选择旧式或现代实现方式
- 04审查 C++ 惯用法的采用情况
安装
复制下面的命令,在终端中运行。
$
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详细介绍
Modern 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 | 概念 + requires | 约束和错误信息更易读 |
| 错误码 + 输出参数 | std::expected<T, E> | 可组合,错误处理类型安全 |
union | std::variant | 类型安全,不会产生隐式未定义行为 |
原始 mutex.lock()/unlock() | std::scoped_lock | 异常安全,不会死锁 |
std::thread | std::jthread | 自动汇合,支持停止令牌 |
assert() 宏 | contract_assert(C++26) | 工具可见,可配置 |
| 手动 CRTP | 推导 this(C++23) | 更简单,无模板样板代码 |
| 宏代码生成 | 反射(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,编译器支持成熟)
| 特性 | 替代内容 | 标准 |
|---|---|---|
概念 + requires | SFINAE、enable_if | C++20 |
| 范围 + 视图 | 原始迭代器循环 | C++20 |
std::span<T> | 指针 + 长度 | C++20 |
std::format | sprintf、iostream 链式调用 | C++20 |
三路比较 <=> | 手动编写比较运算符 | C++20 |
std::jthread | std::thread + 手动汇合 | C++20 |
| 指定初始化器 | 按位置初始化结构体 | C++20 |
std::expected<T,E> | 错误码、边界处的异常 | C++23 |
std::print / std::println | printf、std::cout << | C++23 |
推导 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++ — 使用
-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST,以约 0.3% 的开销进行边界检查 - 在 CI 中使用消毒器 — 至少使用 ASan + UBSan;并发代码使用 TSan
- 警告标志 —
-Wall -Wextra -Wpedantic -Werror
第 3 级:规划采用(C++26,值得围绕其重构)
反射是 C++26 中最具变革性的单项特性。它消除了:
- 序列化样板代码(一个通用函数即可替代每个结构体的
to_json) - 代码生成器(protobuf 代码生成、Qt MOC)
- 基于宏的注册,以及枚举转字符串的变通方案
GCC 16(2026 年 4 月)已合并反射。规划新代码时应考虑借助这一特性。
第 4 级:持续关注(C++26,仍需成熟)
- 契约(
pre/post/contract_assert)——优于assert(),但不支持虚函数,编译器支持也有限。谨慎地将其用于新的 API 边界。 - std::execution(发送器/接收器)——功能强大的异步框架,但学习曲线陡峭、没有随附的调度器,文档也不完善。应等待生态系统成熟。
编译器强化快速参考
必备标志(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]] - 优先采用值语义;使用
std::variant替代union,使用enum class替代enum - 在声明时初始化所有变量
接下来阅读
- anti-patterns.md — 完整的遗留代码到现代代码迁移对照表(30 多种模式)
- cpp20-features.md — 概念、范围、span、format、协程
- cpp23-features.md — expected、print、deducing this、flat_map
- cpp26-features.md — 反射、契约、内存安全改进
- compiler-hardening.md — 标志、消毒器、强化版 libc++
- safe-idioms.md — 按漏洞类别整理的安全模式
评论
支持 Markdown