Skip to main content

cpp-coding-standards

基于C++核心指南(isocpp.github.io)的C++编码标准。在编写、审查或重构C++代码时使用,以强制实施现代、安全和惯用的实践。

Zur Installation springen

Quellinformationen

Repository
affaan-m/ECC
Letzte Quellaktivität
3. März 2026 um 06:28
Erkannte Sprache von SKILL.md
Chinesisch
Sterne
264.820
Forks
39.570

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
cpp-coding-standards
description
基于C++核心指南(isocpp.github.io)的C++编码标准。在编写、审查或重构C++代码时使用,以强制实施现代、安全和惯用的实践。
origin
ECC
# C++ 编码标准(C++ 核心准则) 源自 [C++ 核心准则](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines) 的现代 C++(C++17/20/23)综合编码标准。强制执行类型安全、资源安全、不变性和清晰性。 ## 何时使用 * 编写新的 C++ 代码(类、函数、模板) * 审查或重构现有的 C++ 代码 * 在 C++ 项目中做出架构决策 * 在 C++ 代码库中强制执行一致的风格 * 在语言特性之间做出选择(例如,`enum` 对比 `enum class`,原始指针对比智能指针) ### 何时不应使用 * 非 C++ 项目 * 无法采用现代 C++ 特性的遗留 C 代码库 * 特定准则与硬件限制冲突的嵌入式/裸机环境(选择性适配) ## 贯穿性原则 这些主题在整个准则中反复出现,并构成了基础: 1. **处处使用 RAII** (P.8, R.1, E.6, CP.20):将资源生命周期绑定到对象生命周期 2. **默认为不可变性** (P.10, Con.1-5, ES.25):从 `const`/`constexpr` 开始;可变性是例外 3. **类型安全** (P.4, I.4, ES.46-49, Enum.3):使用类型系统在编译时防止错误 4. **表达意图** (P.3, F.1, NL.1-2, T.10):名称、类型和概念应传达目的 5. **最小化复杂性** (F.2-3, ES.5, Per.4-5):简单的代码就是正确的代码 6. **值语义优于指针语义** (C.10, R.3-5, F.20, CP.31):优先按值返回和作用域对象 ## 哲学与接口 (P.\*, I.\*) ### 关键规则 | 规则 | 摘要 | |------|---------| | **P.1** | 直接在代码中表达想法 | | **P.3** | 表达意图 | | **P.4** | 理想情况下,程序应是静态类型安全的 | | **P.5** | 优先编译时检查而非运行时检查 | | **P.8** | 不要泄漏任何资源 | | **P.10** | 优先不可变数据而非可变数据 | | **I.1** | 使接口明确 | | **I.2** | 避免非 const 全局变量 | | **I.4** | 使接口精确且强类型化 | | **I.11** | 切勿通过原始指针或引用转移所有权 | | **I.23** | 保持函数参数数量少 | ### 应该做 ```cpp // P.10 + I.4: Immutable, strongly typed interface struct Temperature { double kelvin; }; Temperature boil(const Temperature& water); ``` ### 不应该做 ```cpp // Weak interface: unclear ownership, unclear units double boil(double* temp); // Non-const global variable int g_counter = 0; // I.2 violation ``` ## 函数 (F.\*) ### 关键规则 | 规则 | 摘要 | |------|---------| | **F.1** | 将有意义的操作打包为精心命名的函数 | | **F.2** | 函数应执行单一逻辑操作 | | **F.3** | 保持函数简短简单 | | **F.4** | 如果函数可能在编译时求值,则将其声明为 `constexpr` | | **F.6** | 如果你的函数绝不能抛出异常,则将其声明为 `noexcept` | | **F.8** | 优先纯函数 | | **F.16** | 对于 "输入" 参数,按值传递廉价可复制类型,其他类型通过 `const&` 传递 | | **F.20** | 对于 "输出" 值,优先返回值而非输出参数 | | **F.21** | 要返回多个 "输出" 值,优先返回结构体 | | **F.43** | 切勿返回指向局部对象的指针或引用 | ### 参数传递 ```cpp // F.16: Cheap types by value, others by const& void print(int x); // cheap: by value void analyze(const std::string& data); // expensive: by const& void transform(std::string s); // sink: by value (will move) // F.20 + F.21: Return values, not output parameters struct ParseResult { std::string token; int position; }; ParseResult parse(std::string_view input); // GOOD: return struct // BAD: output parameters void parse(std::string_view input, std::string& token, int& pos); // avoid this ``` ### 纯函数和 constexpr ```cpp // F.4 + F.8: Pure, constexpr where possible constexpr int factorial(int n) noexcept { return (n <= 1) ? 1 : n * factorial(n - 1); } static_assert(factorial(5) == 120); ``` ### 反模式 * 从函数返回 `T&&` (F.45) * 使用 `va_arg` / C 风格可变参数 (F.55) * 在传递给其他线程的 lambda 中通过引用捕获 (F.53) * 返回 `const T`,这会抑制移动语义 (F.49) ## 类与类层次结构 (C.\*) ### 关键规则 | 规则 | 摘要 | |------|---------| | **C.2** | 如果存在不变式,使用 `class`;如果数据成员独立变化,使用 `struct` | | **C.9** | 最小化成员的暴露 | | **C.20** | 如果你能避免定义默认操作,就这么做(零规则) | | **C.21** | 如果你定义或 `=delete` 任何拷贝/移动/析构函数,则处理所有(五规则) | | **C.35** | 基类析构函数:公开虚函数或受保护非虚函数 | | **C.41** | 构造函数应创建完全初始化的对象 | | **C.46** | 将单参数构造函数声明为 `explicit` | | **C.67** | 多态类应禁止公开拷贝/移动 | | **C.128** | 虚函数:精确指定 `virtual`、`override` 或 `final` 中的一个 | ### 零规则 ```cpp // C.20: Let the compiler generate special members struct Employee { std::string name; std::string department; int id; // No destructor, copy/move constructors, or assignment operators needed }; ``` ### 五规则 ```cpp // C.21: If you must manage a resource, define all five class Buffer { public: explicit Buffer(std::size_t size) : data_(std::make_unique<char[]>(size)), size_(size) {} ~Buffer() = default; Buffer(const Buffer& other) : data_(std::make_unique<char[]>(other.size_)), size_(other.size_) { std::copy_n(other.data_.get(), size_, data_.get()); } Buffer& operator=(const Buffer& other) { if (this != &other) { auto new_data = std::make_unique<char[]>(other.size_); std::copy_n(other.data_.get(), other.size_, new_data.get()); data_ = std::move(new_data); size_ = other.size_; } return *this; } Buffer(Buffer&&) noexcept = default; Buffer& operator=(Buffer&&) noexcept = default; private: std::unique_ptr<char[]> data_; std::size_t size_; }; ``` ### 类层次结构 ```cpp // C.35 + C.128: Virtual destructor, use override class Shape { public: virtual ~Shape() = default; virtual double area() const = 0; // C.121: pure interface }; class Circle : public Shape { public: explicit Circle(double r) : radius_(r) {} double area() const override { return 3.14159 * radius_ * radius_; } private: double radius_; }; ``` ### 反模式 * 在构造函数/析构函数中调用虚函数 (C.82) * 在非平凡类型上使用 `memset`/`memcpy` (C.90) * 为虚函数和重写函数提供不同的默认参数 (C.140) * 将数据成员设为 `const` 或引用,这会抑制移动/拷贝 (C.12) ## 资源管理 (R.\*) ### 关键规则 | 规则 | 摘要 | |------|---------| | **R.1** | 使用 RAII 自动管理资源 | | **R.3** | 原始指针 (`T*`) 是非拥有的 | | **R.5** | 优先作用域对象;不要不必要地在堆上分配 | | **R.10** | 避免 `malloc()`/`free()` | | **R.11** | 避免显式调用 `new` 和 `delete` | | **R.20** | 使用 `unique_ptr` 或 `shared_ptr` 表示所有权 | | **R.21** | 除非共享所有权,否则优先 `unique_ptr` 而非 `shared_ptr` | | **R.22** | 使用 `make_shared()` 来创建 `shared_ptr` | ### 智能指针使用 ```cpp // R.11 + R.20 + R.21: RAII with smart pointers auto widget = std::make_unique<Widget>("config"); // unique ownership auto cache = std::make_shared<Cache>(1024); // shared ownership // R.3: Raw pointer = non-owning observer void render(const Widget* w) { // does NOT own w if (w) w->draw(); } render(widget.get()); ``` ### RAII 模式 ```cpp // R.1: Resource acquisition is initialization class FileHandle { public: explicit FileHandle(const std::string& path) : handle_(std::fopen(path.c_str(), "r")) { if (!handle_) throw std::runtime_error("Failed to open: " + path); } ~FileHandle() { if (handle_) std::fclose(handle_); } FileHandle(const FileHandle&) = delete; FileHandle& operator=(const FileHandle&) = delete; FileHandle(FileHandle&& other) noexcept : handle_(std::exchange(other.handle_, nullptr)) {} FileHandle& operator=(FileHandle&& other) noexcept { if (this != &other) { if (handle_) std::fclose(handle_); handle_ = std::exchange(other.handle_, nullptr); } return *this; } private: std::FILE* handle_; }; ``` ### 反模式 * 裸 `new`/`delete` (R.11) * C++ 代码中的 `malloc()`/`free()` (R.10) * 在单个表达式中进行多次资源分配 (R.13 -- 异常安全风险) * 在 `unique_ptr` 足够时使用 `shared_ptr` (R.21) ## 表达式与语句 (ES.\*) ### 关键规则 | 规则 | 摘要 | |------|---------| | **ES.5** | 保持作用域小 | | **ES.20** | 始终初始化对象 | | **ES.23** | 优先 `{}` 初始化语法 | | **ES.25** | 除非打算修改,否则将对象声明为 `const` 或 `constexpr` | | **ES.28** | 使用 lambda 进行 `const` 变量的复杂初始化 | | **ES.45** | 避免魔法常量;使用符号常量 | | **ES.46** | 避免有损的算术转换 | | **ES.47** | 使用 `nullptr` 而非 `0` 或 `NULL` | | **ES.48** | 避免强制类型转换 | | **ES.50** | 不要丢弃 `const` | ### 初始化 ```cpp // ES.20 + ES.23 + ES.25: Always initialize, prefer {}, default to const const int max_retries{3}; const std::string name{"widget"}; const std::vector<int> primes{2, 3, 5, 7, 11}; // ES.28: Lambda for complex const initialization const auto config = [&] { Config c; c.timeout = std::chrono::seconds{30}; c.retries = max_retries; c.verbose = debug_mode; return c; }(); ``` ### 反模式 * 未初始化的变量 (ES.20) * 使用 `0` 或 `NULL` 作为指针 (ES.47 -- 使用 `nullptr`) * C 风格强制类型转换 (ES.48 -- 使用 `static_cast`、`const_cast` 等) * 丢弃 `const` (ES.50) * 没有命名常量的魔法数字 (ES.45) * 混合有符号和无符号算术 (ES.100) * 在嵌套作用域中重用名称 (ES.12) ## 错误处理 (E.\*) ### 关键规则 | 规则 | 摘要 |
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen