C++ 编码标准(C++ 核心准则)
源自 C++ 核心准则 的现代 C++(C++17/20/23)综合编码标准。强制执行类型安全、资源安全、不变性和清晰性。
何时使用
- 编写新的 C++ 代码(类、函数、模板)
- 审查或重构现有的 C++ 代码
- 在 C++ 项目中做出架构决策
- 在 C++ 代码库中强制执行一致的风格
- 在语言特性之间做出选择(例如,
enum对比enum class,原始指针对比智能指针)
何时不应使用
- 非 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.*)
关键规则
应该做
不应该做
函数 (F.*)
关键规则
参数传递
纯函数和 constexpr
反模式
- 从函数返回
T&&(F.45) - 使用
va_arg/ C 风格可变参数 (F.55) - 在传递给其他线程的 lambda 中通过引用捕获 (F.53)
- 返回
const T,这会抑制移动语义 (F.49)
类与类层次结构 (C.*)
关键规则
零规则
五规则
类层次结构
反模式
- 在构造函数/析构函数中调用虚函数 (C.82)
- 在非平凡类型上使用
memset/memcpy(C.90) - 为虚函数和重写函数提供不同的默认参数 (C.140)
- 将数据成员设为
const或引用,这会抑制移动/拷贝 (C.12)
资源管理 (R.*)
关键规则
智能指针使用
RAII 模式
反模式
- 裸
new/delete(R.11) - C++ 代码中的
malloc()/free()(R.10) - 在单个表达式中进行多次资源分配 (R.13 -- 异常安全风险)
- 在
unique_ptr足够时使用shared_ptr(R.21)
表达式与语句 (ES.*)
关键规则
初始化
反模式
- 未初始化的变量 (ES.20)
- 使用
0或NULL作为指针 (ES.47 -- 使用nullptr) - C 风格强制类型转换 (ES.48 -- 使用
static_cast、const_cast等) - 丢弃
const(ES.50) - 没有命名常量的魔法数字 (ES.45)
- 混合有符号和无符号算术 (ES.100)
- 在嵌套作用域中重用名称 (ES.12)
错误处理 (E.*)
关键规则
异常层次结构
反模式
- 抛出内置类型,如
int或字符串字面量 (E.14) - 按值捕获(有切片风险) (E.15)
- 静默吞掉错误的空 catch 块
- 使用异常进行流程控制 (E.3)
- 基于全局状态(如
errno)的错误处理 (E.28)
常量与不可变性 (Con.*)
所有规则
并发与并行 (CP.*)
关键规则
安全加锁
多个互斥量
反模式
- 使用
volatile进行同步 (CP.8 -- 它仅用于硬件 I/O) - 分离线程 (CP.26 -- 生命周期管理变得几乎不可能)
- 未命名的锁保护:
std::lock_guard<std::mutex>(m);会立即销毁 (CP.44) - 调用回调时持有锁 (CP.22 -- 死锁风险)
- 没有深厚专业知识就进行无锁编程 (CP.100)
模板与泛型编程 (T.*)
关键规则
概念 (C++20)
反模式
- 在可见命名空间中使用无约束模板 (T.47)
- 特化函数模板而非重载 (T.144)
- 在
constexpr足够时使用模板元编程 (T.120) - 使用
typedef而非using(T.43)
标准库 (SL.*)
关键规则
枚举 (Enum.*)
关键规则
源文件与命名 (SF., NL.)
关键规则
头文件防护
命名约定
反模式
- 在头文件的全局作用域内使用
using namespace std;(SF.7) - 依赖包含顺序的头文件 (SF.10, SF.11)
- 匈牙利命名法,如
strName、iCount(NL.5) - 宏以外的事物使用 ALL_CAPS (NL.9)
性能 (Per.*)
关键规则
指导原则
反模式
- 在没有性能分析数据的情况下进行优化 (Per.1, Per.6)
- 选择“巧妙”的低级代码而非清晰的抽象 (Per.4, Per.5)
- 忽略数据布局和缓存行为 (Per.19)
快速参考检查清单
在标记 C++ 工作完成之前:
- [ ] 没有裸
new/delete—— 使用智能指针或 RAII (R.11) - [ ] 对象在声明时初始化 (ES.20)
- [ ] 变量默认是
const/constexpr(Con.1, ES.25) - [ ] 成员函数尽可能设为
const(Con.2) - [ ] 使用
enum class而非普通enum(Enum.3) - [ ] 使用
nullptr而非0/NULL(ES.47) - [ ] 没有窄化转换 (ES.46)
- [ ] 没有 C 风格转换 (ES.48)
- [ ] 单参数构造函数是
explicit(C.46) - [ ] 应用了零法则或五法则 (C.20, C.21)
- [ ] 基类析构函数是 public virtual 或 protected non-virtual (C.35)
- [ ] 模板使用概念进行约束 (T.10)
- [ ] 头文件全局作用域内没有
using namespace(SF.7) - [ ] 头文件有包含防护且是自包含的 (SF.8, SF.11)
- [ ] 锁使用 RAII (
scoped_lock/lock_guard) (CP.20) - [ ] 异常是自定义类型,按值抛出,按引用捕获 (E.14, E.15)
- [ ] 使用
'\n'而非std::endl(SL.io.50) - [ ] 没有魔数 (ES.45)


