C++ Coding Standards:101条规则、指南与最佳实践

原始文件: /books/c++/Cpp_Coding_Standards/C++_Coding_Standards.pdf 作者: Herb Sutter, Andrei Alexandrescu 页数: 279页 文件大小: 1.99MB 处理日期: 2026-09-03 处理方式: PDF文本提取(text_based) 状态: done


核心概述

《C++ Coding Standards》由C++标准委员会成员Herb Sutter和STL发明者Andrei Alexandrescu合著,是C++社区最具权威性的编码规范著作。全书以101条独立规则构成,每条规则包含:规则陈述 → 讨论 → 示例 → 异常说明 → 参考文献的完整结构。

本书的核心理念并非简单罗列”应该做什么”,而是深入解释”为什么”,并指出哪些情况下可以合理违反规则。它贯穿了C++从C++98到C++11的演进思想,对现代C++编程实践具有持久指导价值。

内容架构

第一部分:组织与政策问题(第0-4条)

  • 第0条:别纠结细枝末节——明确什么不应该标准化,避免过度规范化
  • 第1条:在最高警告级别下干净编译——编译器警告是免费的分析工具
  • 第2条:使用自动化构建系统——消除人为构建错误
  • 第3条:使用版本控制系统——团队协作的基础设施
  • 第4条:投入代码审查——代码审查是最有效的缺陷发现机制

第二部分:设计风格(第5-13条)

  • 第5条:一个实体一个职责——单一职责原则
  • 第6条:正确性、简洁性和清晰度优先——不要过早优化
  • 第7条:知晓何时以及如何进行可扩展性编程
  • 第8条:不要过早优化——经典命题,强调测量驱动优化
  • 第9条:不要过早 pessimize——避免不必要的性能牺牲
  • 第10条:最小化全局和共享数据——全局状态是万恶之源
  • 第11条:隐藏信息——封装原则
  • 第12条:知晓何时以及如何进行并发编程
  • 第13条:确保资源被对象拥有,使用显式RAII和智能指针——C++资源管理的核心范式

第三部分:编码风格(第14-24条)

  • 第14条:优先使用编译期和链接期错误而非运行时错误
  • 第15条:主动使用const——const是正确的软件工程的基石
  • 第16条:避免宏——用模板、inline函数、enum代替
  • 第17条:避免魔术数字——用命名常量
  • 第18条:尽可能局部化变量声明
  • 第19条:始终初始化变量
  • 第20条:避免长函数和深层嵌套
  • 第21条:避免跨编译单元的初始化依赖
  • 第22条:最小化定义依赖,避免循环依赖
  • 第23条:让头文件自给自足
  • 第24条:始终编写内部#include保护,永不编写外部#include保护

第四部分:函数与运算符(第25-31条)

  • 第25条:通过值、(智能)指针或引用恰当接受参数
  • 第26条:保持重载运算符的自然语义
  • 第27条:偏好算术和赋值运算符的标准形式
  • 第28条:偏好++和—的标准形式,优先使用前缀形式
  • 第29条:考虑重载以避免隐式类型转换
  • 第30条:避免重载&&、||、逗号运算符
  • 第31条:不要编写依赖函数参数求值顺序的代码

第五部分:类设计与继承(第32-46条)

  • 第32条:清楚你正在编写什么类型的类
  • 第33条:偏好最小化类而非单体类
  • 第34条:偏好组合而非继承
  • 第35条:避免从非设计为基类的类继承
  • 第36条:优先提供抽象接口
  • 第37条:公有继承是可替换性。继承不是为了复用,而是为了被复用
  • 第38条:安全地进行重写
  • 第39条:考虑让虚函数非公有,让公有函数非虚
  • 第40条:避免提供隐式转换
  • 第41条:数据成员设为private,行为less聚合体(C风格struct)除外
  • 第42条:不要泄露内部实现
  • 第43条:审慎使用pimpl
  • 第44条:优先编写非成员非友元函数
  • 第45条:始终同时提供new和delete
  • 第46条:如果提供任意类特定new,提供所有标准形式

第六部分:构造、析构与复制(第47-56条)

  • 第47条:按相同顺序定义和初始化成员变量
  • 第48条:在构造函数中偏好初始化而非赋值
  • 第49条:避免在构造函数和析构函数中调用虚函数
  • 第50条:使基类析构函数公有且虚,或受保护且非虚
  • 第51条:析构函数、内存释放和swap永不失败
  • 第52条:一致地拷贝和销毁
  • 第53条:显式启用或禁用拷贝
  • 第54条:避免切割。在基类中考虑Clone而非拷贝
  • 第55条:偏好赋值运算符的标准形式
  • 第56条:在合适时提供无失败swap(并正确提供)

第七部分:命名空间与模块(第57-63条)

  • 第57条:将类型及其非成员函数接口保持在同一命名空间
  • 第58条:除非专门设计协同工作,否则将类型和函数放在不同命名空间
  • 第59条:不要在头文件或#include之前编写命名空间using
  • 第60条:避免在不同模块中分配和释放内存
  • 第61条:不要在头文件中定义有链接实体的内容
  • 第62条:不要让异常跨模块边界传播
  • 第63条:在模块接口中使用足够可移植的类型

第八部分:模板与泛型(第64-67条)

  • 第64条:审慎混合静态和动态多态
  • 第65条:有意且显式地进行定制
  • 第66条:不要特化函数模板
  • 第67条:不要编写无意中的非泛型代码

第九部分:错误处理与异常(第68-75条)

  • 第68条:自由使用断言来记录内部假设和不变量
  • 第69条:建立合理的错误处理策略并严格遵守
  • 第70条:区分错误与非错误
  • 第71条:设计并编写错误安全代码
  • 第72条:优先使用异常报告错误
  • 第73条:按值抛出,按引用捕获
  • 第74条:适当报告、处理和转换错误
  • 第75条:避免异常规范

第十部分:STL容器(第76-82条)

  • 第76条:默认使用vector。否则选择适当的容器
  • 第77条:使用vector和string替代数组
  • 第78条:使用vector(string::c_str)与非C++ API交换数据
  • 第79条:容器中只存储值和智能指针
  • 第80条:优先push_back扩展序列
  • 第81条:优先范围操作而非单元素操作
  • 第82条:使用标准惯用法真正缩小容量和删除元素

第十一部分:STL算法(第83-90条)

  • 第83条:使用检查型STL实现
  • 第84条:优先算法调用而非手写的循环
  • 第85条:使用正确的STL搜索算法
  • 第86条:使用正确的STL排序算法
  • 第87条:使谓词为纯函数
  • 第88条:使用transform替代手工循环
  • 第89条:不要通过迭代器无效化来利用实现细节
  • 第90条:理解标准库中迭代器的分类层次

第十二部分:数值与字符串(第91-97条)

  • 第91条:避免浮点比较
  • 第92条:避免使用rand()
  • 第93条:避免使用C样式字符串
  • 第94条:用string替代char*用于文本
  • 第95条:用wstring替代string用于多字节文本
  • 第96条:使用string::find而非手动字符遍历
  • 第97条:理解string的性能特征

第十三部分:国际化与本地化(第98-101条)

  • 第98条:考虑国际化设计
  • 第99条:不要硬编码文本
  • 第100条:考虑使用本地化框架
  • 第101条:测试本地化代码

核心要点提炼

组织层面

  1. 编译器是你的朋友:开启最高警告级别,让编译器帮你发现问题
  2. 代码审查胜过一切:静态分析工具无法替代人工审查
  3. 自动化构建是基础设施:减少人为错误,提高可重现性

设计层面

  1. 正确性 > 性能 > 抽象:三层优先级不可颠倒
  2. RAII是C++资源管理的灵魂:所有资源管理都应该围绕RAII展开
  3. 组合优于继承:继承是强烈的耦合,组合提供更大的灵活性
  4. 最小化全局状态:全局变量是并发和测试的头号敌人

编码层面

  1. const贯穿始终:const正确性是C++安全编程的基础
  2. 头文件自给自足:每个头文件应能独立编译
  3. 避免隐式转换:隐式转换是bug的主要来源
  4. 按值抛出,按引用捕获:这是异常处理的标准范式

STL层面

  1. vector是默认选择:除非有明确理由,否则使用vector
  2. 算法优于循环:标准算法更健壮、更易读、更易优化
  3. 容器存储值或智能指针:裸指针不应存储在容器中

与其他知识的关联

  • Effective C++ —— Scott Meyers的经典之作,与本书形成互补,Effective C++更侧重C++编程技巧,本书更侧重工程规范
  • C++并发编程实战 —— 本书第12条关于并发的原则在此书中有详细展开
  • STL源码剖析 —— 理解STL内部实现有助于更好地理解本书关于STL使用的建议
  • Modern C++ Design —— Andrei Alexandrescu的另一部作品,与本书的泛型编程建议一脉相承

行动建议

  1. 团队层面:将本书的核心规则转化为团队的编码规范文档
  2. 工具层面:配置clang-tidy或cppcheck,自动检查常见违规
  3. 代码审查:在CR清单中加入本书的关键检查点
  4. 持续学习:逐条阅读并讨论,每条规则背后都有丰富的讨论和例外

本书是C++工程师案头必备的参考书,建议反复查阅而非一次性读完。