
关于
基于 C++ 核心指南(isocpp.github.io)的 C++ 编码标准。在编写、审查或重构 C++ 代码时使用。
name: cpp-coding-standards description: 基于 C++ Core Guidelines (isocpp.github.io) 的 C++ 编码规范。用于编写、审查或重构 C++ 代码时,强制执行现代、安全且符合惯用法的实践。 origin: ECC
C++ 编码规范(C++ Core Guidelines)
基于 C++ Core Guidelines 的现代 C++(C++17/20/23)综合编码规范。强制执行类型安全、资源安全、不可变性和代码清晰性。
适用场景
- 编写新的 C++ 代码(类、函数、模板)
- 审查或重构现有 C++ 代码
- 在 C++ 项目中做架构决策
- 在 C++ 代码库中强制统一风格
- 在语言特性之间做选择(如
enumvsenum class,裸指针 vs 智能指针)
不适用场景
- 非 C++ 项目
- 无法采用现代 C++ 特性的遗留 C 代码库
- 特定指南与硬件约束冲突的嵌入式/裸机环境(可选择性采用)
核心原则
以下主题贯穿整个指南,构成基础:
- RAII 无处不在(P.8, R.1, E.6, CP.20):将资源生命周期绑定到对象生命周期
- 默认不可变(P.10, Con.1-5, ES.25):以
const/constexpr为起点;可变性是例外 - 类型安全(P.4, I.4, ES.46-49, Enum.3):利用类型系统在编译期防止错误
- 表达意图(P.3, F.1, NL.1-2, T.10):名称、类型和概念应传达目的
- 最小化复杂度(F.2-3, ES.5, Per.4-5):简单的代码就是正确的代码
- 值语义优于指针语义(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 | 保持函数参数数量少 |
正确做法
// P.10 + I.4: Immutable, strongly typed interface
struct Temperature {
double kelvin;
};
Temperature boil(const Temperature& water);
错误做法
// 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 | 永远不要返回指向局部对象的指针或引用 |
参数传递
// 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
// 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 | 基类析构函数:public virtual
