【C/C++】C++ 编程规范:101条规则准则与最佳实践

发布于:2025-06-25 ⋅ 阅读:(26) ⋅ 点赞:(0)

C++ 编程规范:101条规则准则与最佳实践

引言

C++ 是一门强大而复杂的语言,能高效控制硬件,也能写出优雅抽象。然而,正因其复杂性,项目中若缺乏统一规范,极易陷入混乱、难维护、易出错的泥潭。

本文总结了 101条 C++ 编程规范与最佳实践,涵盖 命名、结构、内存管理、多线程、异常、安全、性能等多个维度,旨在帮助开发者构建高质量、可维护、可扩展的 C++ 项目。


一、命名与风格(Rules 1–10)

# 规则 简要建议
1 类名使用大驼峰 PascalCase ThreadPool,提高可辨识性
2 变量名使用小驼峰 camelCase 例:logFilePath,区分于类名
3 常量用 ALL_CAPS + _ 分隔 强化不变含义,如 MAX_BUFFER_SIZE
4 命名需语义明确 避免 data, tmp,使用 configFilePath 更清晰
5 缩写仅限通用缩写 idx, buf,尽量使用全称提升可读性
6 函数名用动词 + 名词 例如 loadConfig() 表意清晰
7 命名空间用小写 network::socket,避免歧义
8 接口类加 I 前缀(可选) ILogger,强调为接口
9 成员变量加前缀/后缀 m__ 表示成员变量,增强可读性
10 enum class 替代裸 enum 强类型更安全,防止命名冲突

二、代码结构与风格(Rules 11–20)

# 规则 简要建议
11 每个头文件只声明一个模块 避免多义性,便于编译与复用
12 使用 #pragma once 或 include guard 防止重复包含
13 include 顺序:本地 > 第三方 > STL 增强可读性与可维护性
14 避免头文件中包含过多实现 使用前向声明可减少依赖
15 类/函数应单一职责 有助于测试与扩展
16 控制函数长度 < 60 行 超过建议拆分子函数
17 控制每个文件长度 < 2000 行 模块化设计更清晰
18 每行不超过 120 字符 保证阅读体验,特别在 review 时
19 使用 4 空格缩进,禁止制表符 统一格式,防止跨平台混乱
20 所有控制结构都用 {} 包围 防止隐式逻辑错误,如单行 if 陷阱

三、类设计与对象管理(Rules 21–30)

# 规则 建议
21 所有成员变量应为私有 使用 getter/setter 访问
22 提供合理构造/析构函数 保证资源初始化与释放对称
23 禁用复制/移动时应 = delete 明确意图,防止误用
24 explicit 阻止隐式转换 explicit Config(std::string path)
25 避免裸指针作为成员 使用 unique_ptr/shared_ptr 安全管理
26 构造函数不做复杂逻辑 仅初始化,不处理业务
27 基类析构函数应为 virtual 否则 delete 派生类有 UB
28 优先使用组合而非继承 组合更灵活、低耦合
29 不使用多重继承(除非纯接口) 降低复杂度,避免菱形继承问题
30 避免深层继承结构 建议控制在 2 层以内

四、函数与模板(Rules 31–40)

# 规则 建议
31 参数多于 3 个建议封装结构体 提高可读性与扩展性
32 参数传递规则明确 小型值传递,大型对象引用
33 函数返回值推荐智能指针或值传递 避免裸指针和资源泄露
34 函数要写用途注释 特别是公共接口或库函数
35 模板逻辑应轻量,避免过多嵌套 编译时间压力大时尤需注意
36 合理使用 auto 简化类型 不影响语义的地方使用
37 模板中加入 static_assert 限定 增强类型安全性
38 使用 constexpr 提升编译期能力 如常量计算函数
39 控制模板递归深度 编译器对深层模板支持有限
40 模板尽可能放 header 中定义 避免链接错误(ODR 问题)

五、内存管理(Rules 41–50)

# 规则 建议
41 禁止裸 new/delete make_unique/make_shared 替代
42 所有资源管理用 RAII 让析构自动释放资源
43 禁止手动 free/close 封装在类中自动释放
44 指针拥有权应清晰 避免 ownership 混乱
45 避免 shared_ptr 在多线程竞争 使用 atomic_shared_ptr 或避免频繁共享
46 使用工具检测泄漏 如 Valgrind、ASan
47 使用智能指针区分 shared/unique 语义 更清晰,更安全
48 不要传值传递 shared_ptr const& 降低引用计数开销
49 使用容器代替裸数组 STL 容器更安全
50 类封装资源释放逻辑 遵守 RAII,职责清晰

六、异常处理与错误传递(Rules 51–60)

# 规则 建议
51 尽量避免使用异常 推荐 error code / Result<T> 结构
52 异常必须 catch 并处理 记录日志,避免 silent fail
53 不使用 catch (...) 易隐藏逻辑错误
54 构造函数中不抛异常 否则无法确定对象是否成功创建
55 明确错误处理模块 集中统一处理错误
56 注释中注明错误返回 增强调用方对异常的理解
57 编写无副作用函数 降低调试/测试成本
58 日志输出必须有上下文 包括文件名/函数名/线程信息
59 接口错误向上传递 不要在底层吞掉问题
60 异常路径不得影响主逻辑性能 异常处理应轻量快捷

七、多线程与并发(Rules 61–70)

# 规则 建议
61 封装线程操作 避免裸用 std::thread
62 原子操作使用 std::atomic 避免竞态条件
63 使用细粒度锁或无锁结构 提升性能,减少死锁
64 使用 lock_guard 管理锁 自动加锁释放
65 不捕获局部引用传入线程 否则线程中变量悬空
66 避免死锁 控制锁顺序,使用 std::scoped_lock
67 避免全局变量并发读写 用线程局部存储或加锁保护
68 构建线程池封装并发任务 避免线程爆炸与资源浪费
69 不得在对象析构前 detach 线程 否则存在野线程
70 使用条件变量控制等待 避免忙等浪费 CPU

八、性能优化(Rules 71–80)

# 规则 建议
71 优化热点路径 代码中使用 likely / unlikely
72 std::move 转移资源 防止不必要的拷贝
73 使用 emplace_back 避免对象额外构造拷贝
74 使用 reserve 预分配空间 降低 reallocation 成本
75 避免频繁申请释放内存 推荐对象池或内存复用
76 避免虚函数热路径中使用 可用策略模式等替代
77 小函数可使用 inline 减少函数调用开销
78 注意 ABI 兼容性 跨平台或多版本部署需考虑
79 无序容器快于有序容器 unordered_map 通常优于 map
80 使用 string_view 避免拷贝 尤其在字符串解析场景中

九、安全与健壮性(Rules 81–90)

# 规则 建议
81 所有输入必须校验合法性 防止越界、注入等问题
82 检查整数溢出风险 使用安全加法函数
83 禁止数组越界访问 at() 或容器封装
84 使用 RAII 管理资源 防止内存泄漏或悬空指针
85 IO 操作必须检查返回值 否则容易逻辑错误
86 不在库中使用 exit/abort 破坏调用者行为
87 库中不处理 UI/日志 由上层决定策略
88 接口遵循最小权限原则 降低攻击面与耦合
89 使用静态分析工具辅助检查 如 clang-analyzer, cppcheck
90 禁止未定义行为写法 避免 UB 问题,如越界指针、悬空引用等

十、工程实践与工具链(Rules 91–101)

# 规则 建议
91 接入持续集成(CI) 自动编译与检查保障质量
92 使用单元测试框架 推荐 GTest/GMock
93 使用代码覆盖率工具 识别未测试路径
94 强制统一代码格式化工具 推荐 clang-format
95 接入内存检测工具 如 AddressSanitizer
96 使用 CMake 管理构建 跨平台统一构建系统
97 单元测试覆盖率 >= 80% 提升可靠性
98 所有代码需 Code Review 防止低级错误
99 接入日志和监控模块 如 Prometheus、Grafana
100 所有模块应可独立构建测试 降低耦合度
101 每半年重审一次规范 适应团队与项目演化

网站公告

今日签到

点亮在社区的每一天
去签到