C++ Core Guidelines 整理目录
- 哲学部分
- 接口(Interface)部分
- 函数部分
- 类和类层次结构部分
- 枚举部分
- 资源管理部分
- 表达式和语句部分
- 性能部分
- 并发和并行
- 错误处理
- 常量和不可变性
- 泛型编程
- 源文件
- 命名和布局建议
- 标准库
The Standard Library
标准库规则总结
SL.1: Use libraries wherever possible
- 翻译: 尽可能使用库.
- 原因: 使用已有的库可以减少代码量, 提高代码的可靠性, 并且利用经过优化和测试的现有解决方案.
SL.2: Prefer the standard library to other libraries
- 翻译: 优先选择标准库而不是其他库.
- 原因: 标准库与 C++语言紧密结合, 提供了高效的实现和良好的兼容性, 同时减少了项目对外部依赖的复杂度.
SL.3: Do not add non-standard entities to namespace std
- 翻译: 不要向命名空间
std
中添加非标准实体. - 原因: 命名空间
std
是为标准库保留的, 向其中添加自定义实体可能会导致未定义行为或编译错误, 影响程序的可移植性和稳定性.
SL.4: Use the standard library in a type-safe manner
- 翻译: 使用标准库时确保类型安全.
- 原因: 类型安全有助于避免潜在的编程错误, 如类型混淆和内存越界访问等, 保证程序的健壮性和安全性.
SL.con: 容器规则总结
SL.con.1: Prefer using STL array
or vector
instead of a C array
- 翻译: 优先使用 STL 的
array
或vector
而不是 C 数组. - 原因: STL 容器提供更安全的操作和额外的功能, 如自动内存管理, 边界检查等, 减少错误并提高代码质量.
SL.con.2: Prefer using STL vector
by default unless you have a reason to use a different container
- 翻译: 默认情况下优先使用 STL 的
vector
, 除非你有理由选择不同的容器. - 原因:
vector
是一个通用且高效的动态数组实现, 适用于大多数需要存储和操作元素集合的场景, 除非特定情况要求不同的特性(例如快速插入/删除).
SL.con.3: Avoid bounds errors
- 翻译: 避免边界错误.
- 原因: 边界错误(如访问超出数组或容器范围的元素)是程序中常见的问题, 可能导致未定义行为. 使用 STL 容器的方法有助于避免这些错误, 因为它们通常提供了边界检查功能.
SL.con.4: don’t use memset
or memcpy
for arguments that are not trivially-copyable
- 翻译: 对于非平凡可复制的参数, 不要使用
memset
或memcpy
. - 原因:
memset
和memcpy
不考虑对象的内部结构, 对于包含指针或其他复杂成员的对象, 直接使用这些函数进行内存操作可能会导致资源泄露或数据损坏. 应使用更为安全和类型友好的方法来处理对象的复制和初始化.
SL.str: String 规则
SL.str.1: Use std::string
to own character sequences
- 翻译: 使用
std::string
来拥有字符序列. - 原因:
std::string
提供了自动内存管理和丰富的字符串操作功能, 确保了安全性与便利性, 避免手动管理字符数组带来的复杂性和潜在错误.
SL.str.2: Use std::string_view
or gsl::span<char>
to refer to character sequences
- 翻译: 使用
std::string_view
或gsl::span<char>
来引用字符序列. - 原因: 这些类型提供了一种轻量级的方式引用字符串数据, 而无需复制. 它们非常适合需要传递或临时查看字符串内容的场景, 提高了性能和灵活性.
SL.str.3: Use zstring
or czstring
to refer to a C-style, zero-terminated, sequence of characters
- 翻译: 使用
zstring
或czstring
来引用 C 风格的零终止字符序列. - 原因: 当必须处理 C 风格字符串时, 使用这些类型可以提高代码的安全性和可读性, 同时保持与现有 C 库函数的兼容性.
SL.str.4: Use char*
to refer to a single character
- 翻译: 使用
char*
来引用单个字符. - 原因: 在某些情况下(如低级别编程), 直接使用指针可能是必要的. 但需要注意的是, 这种用法应仅限于确实需要的情况, 并且要小心管理内存以避免错误.
SL.str.5: Use std::byte
to refer to byte values that do not necessarily represent characters
- 翻译: 使用
std::byte
来引用不一定表示字符的字节值. - 原因:
std::byte
专门用于处理非字符数据的字节操作, 避免了与字符相关的假设, 提供了更清晰和安全的操作方式.
SL.str.10: Use std::string
when you need to perform locale-sensitive string operations
- 翻译: 当你需要执行与区域设置相关的字符串操作时, 使用
std::string
. - 原因:
std::string
支持区域设置敏感的操作, 如大小写转换和字符分类, 这对于国际化应用非常重要, 确保了字符串处理的一致性和正确性.
SL.str.11: Use gsl::span<char>
rather than std::string_view
when you need to mutate a string
- 翻译: 当你需要修改字符串时, 使用
gsl::span<char>
而不是std::string_view
. - 原因:
gsl::span<char>
允许对底层数据进行修改, 而std::string_view
是只读的. 在需要修改字符串内容的情况下, 选择合适的工具可以避免不必要的数据复制并提高效率.
SL.str.12: Use the s
suffix for string literals meant to be standard-library string
s
-
翻译: 对于打算作为标准库字符串使用的字符串字面量, 使用
s
后缀. -
原因: 使用
s
后缀可以方便地将字符串字面量转换为std::string
类型, 简化了从 C 风格字符串到 C++标准库字符串的转换过程, 提升了代码的清晰度和一致性. -
示例:
auto str = "Hello, world!"s; // str 是一个 std::string 对象 auto cstr = "Hello, world!"; // cstr 是一个 char* 指针
SL.io: Iostream 规则
SL.io.1: Use character-level input only when you have to
- 翻译: 仅在必要时使用字符级别的输入.
- 原因: 字符级别的输入处理通常比行级别或块级别的输入更复杂且容易出错. 只有在确实需要逐字符处理的情况下才应使用这种方法.
SL.io.2: When reading, always consider ill-formed input
- 翻译: 在读取时, 始终考虑不规范的输入.
- 原因: 输入数据可能包含错误或不符合预期格式的情况. 提前考虑并处理这些情况可以提高程序的健壮性和容错能力, 避免因意外输入导致崩溃或其他问题.
SL.io.3: Prefer iostreams for I/O
- 翻译: 优先选择
iostream
进行 I/O 操作. - 原因: C++的
iostream
库提供了类型安全, 易于使用的接口, 并支持广泛的输入输出需求. 相比 C 风格的 I/O 函数, 它减少了错误的可能性并提高了代码的可维护性.
SL.io.10: Unless you use printf
-family functions call ios_base::sync_with_stdio(false)
- 翻译: 如果你不使用
printf
系列函数, 调用ios_base::sync_with_stdio(false)
. - 原因: 默认情况下, C++的 iostream 与 C 的 stdio 同步, 这会带来性能开销. 如果确认不会使用
printf
等 C 风格的 I/O 函数, 可以通过禁用同步来提高性能.
SL.io.50: Avoid endl
- 翻译: 避免使用
endl
. - 原因:
endl
不仅插入换行符, 还会刷新缓冲区, 频繁使用会导致性能下降. 推荐直接使用\n
来插入换行符, 并在必要时手动刷新缓冲区以控制性能影响.
SL.C: C 标准库规则
SL.C.1: Don’t use setjmp/longjmp
- 翻译: 不要使用
setjmp
/longjmp
. - 原因:
setjmp
和longjmp
破坏了正常的函数调用栈管理, 可能导致资源泄漏和其他难以调试的问题. C++提供了异常机制来处理错误和异常情况, 建议使用异常处理机制而不是setjmp
/longjmp
.