关于 cpp-systems
面向 C++ 系统与库开发和审查的技能,以 C++17 为基线,并在适用处说明 C++20 特性。重点包括明确资源所有权、兼容性、遵循仓库约定,以及通过构建、分析和测试进行验证。
主要功能
- 01RAII 与所有权指引
- 02C++17 基线及 C++20 说明
- 03API 与 ABI 兼容实践
- 04仓库约定与工具链
- 05构建、分析及消毒器检查
适用场景
- 01实现 C++ 库变更
- 02审查资源生命周期与所有权
- 03维护公共 API 和 ABI
- 04验证构建与多线程代码
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ iliaal/ ai-skills --skill cpp-systems安装后在 Claude Code 中输入/cpp-systems确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
SPEC.mdreferences/api-and-abi.mdcmake-and-tooling.mdconcurrency-and-verification.mdlegibility-standard.mdvalue-and-interface-design.md详细介绍
C++ 系统与库
以 C++17 为基线,并在项目标准允许时注明 C++20 特性。对于纯 C(手动管理生命周期、状态枚举、原生扩展),请参阅 ia-c-systems 技能。
工作规则
- 明确资源所有权,并使用 RAII 确保所有退出路径都会释放资源。
- 借用视图的生命周期不得超出其后备存储,并在特殊成员发生变化时检查复制和移动行为。
- 遵循项目的错误处理模型和支持的语言标准。
- 保持 ABI 稳定,避免在持有锁或可能失效的容器迭代器时调用未知回调。
仓库约定优先于本技能
编写代码前,检查 CMakeLists.txt 中的 CXX_STANDARD,阅读 .clang-format 和 .clang-tidy,并阅读相邻的两个翻译单元。若它们与以下规则冲突,以仓库约定为准。
实际可能遇到的冲突:
| 本地约束 | 结果 |
|---|---|
-fno-exceptions | 错误处理使用错误码或类似 expected 的类型。构造函数无法报告可恢复的失败,因此应使用可失败的工厂函数,或构造有效的回退状态。仅当项目的 OOM 策略要求观察空指针并进行恢复时,才使用 new (std::nothrow);若策略是终止程序,则使用普通 new 即可 |
| 标准固定在 C++17 以下 | 不可使用 std::optional、string_view、结构化绑定或 if constexpr;使用前请先确认 |
| 公共头文件要求 ABI 稳定 | 不得更改布局、修改内联函数或添加虚函数:请加载 ABI 参考资料 |
| 嵌入式或 freestanding 目标 | 不使用 RTTI,热路径中不进行动态分配,也可能不使用 STL 容器 |
所有权与 RAII
每项资源都恰有一个所有者,且该所有者是一个会在析构时释放资源的对象。在应用程序代码中直接使用 new 或 delete 属于缺陷。
- 独占所有权使用
std::unique_ptr<T>。它是默认选择;与裸指针相比,开销为零。 - 仅当生命周期确实由多个对象共享,且无法表达为“所有者的生命周期长于使用者”时,才使用
std::shared_ptr<T>。优先级应排在第三,而非第一。 - 使用
std::weak_ptr<T>打破所有权循环。LeakSanitizer 会报告从任何根都无法到达的循环,但不会报告仍可从全局变量或其他已注册根到达的循环;检测结果也因平台和配置而异。不要依赖 Sanitizer 来发现这些问题。 - 裸
T*和T&表示非拥有式观察,用于此角色是正确的。按值接收unique_ptr的参数表示将接管所有权;接收T*的参数则表示不会接管。 - 在新的公共 API 中,借用连续范围使用
std::span<T>(C++20)或“指针加长度”的组合,因为在此处使用const std::vector<T>&会排除其他所有容器。若基线为 C++17,或内部代码的调用方本来就都持有 vector,则使用const std::vector<T>&没问题,也更简单。
零法则:不拥有任何资源的类不声明析构函数、复制操作或移动操作。组合能够自行管理资源的成员,即可免费正确获得全部五个特殊成员。五法则:只要声明了析构函数、复制构造函数、复制赋值运算符、移动构造函数或移动赋值运算符中的任意一个,作者就必须考虑全部五个。用户声明析构函数会抑制隐式移动操作,因此新增析构函数的类可能会悄然从原先的移动转为深拷贝。
规范
- 除非明确要求破坏兼容性,否则保持行为和 API 兼容。修改公共头文件是一个需要做出的决定,不是清理工作。
- 不要为了单个调用点引入模板、继承体系或策略参数。
- 文件使用什么就
#include什么;不要依赖其他头文件的传递性包含。 - 不要在头文件的命名空间作用域使用
using namespace。应使用完全限定名称,或将using限定在函数体内。 - 如果约束迫使你偏离规范,请在偏离处添加注释并说明该约束。
验证
- 使用
-Wall -Wextra -Wpedantic -Wshadow -Wconversion -Werror构建无警告 clang-tidy对差异部分不报告新的问题- 在
-fsanitize=address,undefined下运行测试,且无任何报告 - 本次更改涉及的任何多线程代码都应在 TSan 下测试,且无任何报告;上述警告选项组合无法检测锁误用
clang-format --dry-run --Werror不产生差异- 不新增裸
new/delete;在unique_ptr足够时,不新增shared_ptr - 为其新增析构函数的任何类,都应检查其移动操作
特定任务参考
实现或审查相应行为前,请阅读相关参考文档:
- 对于 const 性、错误、API/ABI 更改、模板或标准库行为,请参阅:value-and-interface-design.md。
- 对于线程、编译器设置、测试或构建分析,请参阅:concurrency-and-verification.md。
适用时,请查阅以下现有专项参考文档:
评论
支持 Markdown