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

基本信息

  • 书名:C++ Coding Standards: 101 Rules, Guidelines, and Best Practices
  • 作者:Herb Sutter, Andrei Alexandrescu
  • 页数:279页
  • 文件大小:1.99MB
  • 原书路径:/books/c++/Cpp_Coding_Standards/C++_Coding_Standards.pdf

书籍概述

本书由C++标准委员会核心成员Herb Sutter和泛型编程大师Andrei Alexandrescu合著,提出了101条C++编码规范,是C++编程实践中最实用的规范参考书。不同于语言规范层面的”应该做什么”,本书聚焦于”如何做才对”,覆盖从编译配置到代码审查的全流程。

全书分为五大主题:组织与策略问题、设计风格、编码风格、函数与运算符、异常处理与资源管理。

核心规则摘要

一、组织与策略问题

规则0:不要纠结细节(知道什么不该标准化)

  • 不是所有东西都需要标准;有些属于个人偏好
  • 团队先就核心原则达成一致,细节可以灵活

规则1:以高警告级别干净编译

  • 开启所有警告并视为错误(-Wall -Werror)
  • 编译失败比运行失败好得多

规则2:使用自动化构建系统

  • Make/CMake等工具确保构建可重复

规则3:使用版本控制系统

  • Git等工具追踪变更历史

规则4:投入代码审查

  • 代码审查是发现bug最有效的手段之一
  • 重点审查设计逻辑,而非格式

二、设计风格

规则5:一个实体承担一个 cohesive 职责

  • 单一职责原则:每个类/函数只做一件事
  • 避免职责混杂导致的复杂性

规则6:正确性、简单性和清晰度优先

  • 正确 > 简单 > 清晰 > 快
  • 不要为了优化而牺牲可读性

规则7:知道何时以及如何为可扩展性编码

  • 为变化做准备,但不要过度设计
  • YAGNI原则:不要过早抽象

规则8:不要过早优化

  • 先测量,再优化
  • 优化必须基于数据而非猜测

规则9:不要过早劣化

  • 避免不必要的复杂性
  • 保持代码简洁比追求通用更重要

规则10:最小化全局和共享数据

  • 全局变量是并发和难以推理的根源
  • 优先使用局部变量和对象封装

规则11:隐藏信息

  • 尽可能减少可见性
  • private > protected > public

规则12:知道何时以及如何为并发编码

  • 线程安全是可选特性,不是默认行为
  • 使用RAII管理锁

规则13:确保资源由对象拥有,使用显式RAII和智能指针

  • RAII是C++资源管理的基石
  • 优先使用unique_ptr/shared_ptr而非裸指针

三、编码风格

规则14:优先编译/链接时错误而非运行时错误

  • 能用static_assert就用
  • 类型检查比运行时断言更好

规则15:主动使用const

  • const是接口契约的一部分
  • const正确性可以防止意外修改

规则16:避免宏

  • 宏没有类型安全,无法调试
  • 用inline函数、template、enum替代

规则17:避免魔术数字

  • 用命名常量替代字面量
  • 提高可读性和可维护性

规则18:尽可能局部声明变量

  • 变量应在首次使用前声明
  • 减少作用域,提高可读性

规则19:总是初始化变量

  • 未初始化变量是bug的来源
  • 用列表初始化确保初始化

规则20:避免长函数,避免深层嵌套

  • 函数应简短 focused
  • 嵌套不超过2-3层

规则21:避免跨编译单元的初始化依赖

  • 静态初始化顺序问题是经典陷阱
  • 用函数内静态变量替代

规则22:最小化定义依赖,避免循环依赖

  • 头文件依赖应形成DAG
  • 使用前向声明减少依赖

规则23:让头文件自给自足

  • 头文件应能独立编译
  • 包含所需的所有依赖

规则24:始终写内部#include guards,从不写外部#include guards

  • 使用#if !defined或#pragma once
  • 不要依赖外部定义的guard宏

四、函数与运算符

规则25:按值、(智能)指针或引用适当取参

  • 小对象按值传递
  • 大对象用const引用
  • 可空参数用指针

规则26:保持重载运算符的自然语义

  • operator==应该是对称的
  • operator<<应该返回ostream引用

规则27:优先使用算术和赋值运算符的标准形式

  • 实现a += b 比 a + b 更高效
  • operator+= 应返回 *this

五、异常处理与资源管理

规则28-30:异常安全级别

  • 基本保证:无资源泄漏,状态合法
  • 强保证:操作成功或无变化
  • 不抛掷保证:永不抛出异常

规则31-35:RAII深化的应用

  • 用智能指针管理动态内存
  • 用lock_guard/unique_lock管理锁
  • 用自定义deleter扩展RAII

关键洞察

  1. 静态检查优于动态检查:能在编译期发现的问题,绝不让它跑到运行时
  2. const是朋友:正确使用const可以捕获大量错误
  3. RAII是C++的灵魂:资源管理必须通过对象生命周期来实现
  4. 简单优于复杂:大多数情况下,简单的代码比复杂的代码更好
  5. 测量驱动优化:优化必须有数据支持,否则只是在猜测

与其他知识的关联

可行动点

  1. 在项目中启用最高警告级别(-Wall -Wextra -Werror)
  2. 用static_assert替代运行时类型检查
  3. 全面使用智能指针,消除裸new/delete
  4. 为所有公有接口添加const正确性标注
  5. 建立代码审查清单,重点关注设计而非格式