admin 2026-07-10 11:50:32 免费看世界杯

代码规范

一些个人习惯而罢了。

头文件

分四部分依次排列

cpp 文件对应的头文件

解决方案内源码可见的头文件

第三方库的头文件

标准库头文件

第三方库用 <> 自己的头文件用 “”

按字典序排序

清理不必要的头文件

C++ 标准库头文件不带扩展名,C 头文件带 .h,C++ 程序中尽量用 C++ 头文件

命名

函数大写驼峰

变量小写驼峰

指针和引用右对齐

成员变量 - m_

指针 - p_

local 静态变量 - s_

静态成员变量不加前缀,因为 T::abc 的用法足以说明该变量的类型

编译期常量 - 大写驼峰,或者全大写,下划线连接

缩写 - 全大写

累计值 - count

字节数 - size

字符串长度 - length

注释

单行注释

12// ...int a; // ...

多行注释

12345/* * ... * ... */int a;

// TODO: Do something

首字母大写

除非是长篇的描述,否则不加句号

使用 does not 而非 doesn't

公式之类非英文的部分用 `` 括起来

对函数、类型的引用以 # 开头

命名空间右大括号后跟注释

较长的 #else 或 #endif 后跟注释

单行死代码用 //,多行用 #if 0

复数:内容物是否是XXX,并且相互独立

Utils/, Defines.h

单数:内容物是否属于XXX的一部分,并且相互耦合

Renderer/, Hash.hpp

类型

可以使用 int 和 char

使用 int16_t 而非 short,使用 uint64_t 而非 unsigned long long

使用 true 和 false 而非 0 和 1 来表示 bool

涉及位运算时使用无符号整数

避免对无符号整数进行可能令其下溢的计算

与第三方库交互时优先遵循该库的参数 / 返回类型

考虑到内存对齐,成员变量应按大小降序排序,不需要严格遵守,重点是不要让类的中间出现填充

按成员变量的声明顺序排列初始化列表,尽量不要用一个成员变量初始化另一个成员变量

成员函数的默认值写在构造函数初始化列表里,没有构造函数则写在声明处

final

成员以 static, public, protected, private 的顺序排列

三五法则

基类析构函数必须为虚函数

重写基类虚函数必须加 override

大括号

不要省略单行代码的大括号

switch 每个 case 都加大括号,大括号内 break / return

其他

4 空格缩进

命名空间内容不缩进

template 为非 template

前向声明

如何传参

对于 sizeof(T) <= 8 的栈类型

直接 copy

对于 sizeof(T) > 8,的栈类型

const &T,禁止对其移动

对于会产生动态内存分配的类型

提供普通参数,内部必须 move,由函数调用者决定 copy 进函数还是 move 进函数

禁止用 std::string_view 参数构造 std::string

禁止用 std::span / std::initializer_list 参数构造 std::vector

如果参数在函数内不存在直接的构造 / 赋值行为

const &T

很多时候我们只需要 void * 和 size,优先用 std::span

如果只需要一个 char *,优先用 const char *

如果同时需要 char * 和 size,优先用 std::string_view

C-style string, std::string 和 std::string_view 会让情况变得复杂

copy 一个 char * 比 copy 一个 std::string_view 快一丢丢,但是缺失了长度信息

比较糟糕的情况就是 std::string.data() 传给 char * 参数,然后在内部以某种方式重新计算长度,产生的开销可能得不偿失

更糟糕的是我们不一定能简单地判断这件事,举个例子,C++20 MSVC STL:

std::fstream 就算用 std::string 构造也只会将参数的 .data() 转发给接受 char * 的重载

std::filesystem::path 用 char * 构造则会在内部用 for 循环计算长度并构造 std::string_view

换个编译器实现说不定就不一样了,换个 C++ 版本说不定也不一样了

Anyway:

if 调用处一定只存在 char *

用 const char *,真要计算长度早晚逃不掉,不如少 copy 点东西

else

if 函数内不需要长度

用 const char *

else

用 std::string_view

当然也可以拉几把倒全用 std::string_view,扣这么细很麻烦而且不一定有意义

STL 只要提供一堆重载就行,我们调库的要考虑的可就多了(

尽量用 assert 代替 if-log-return,C++ 最好的错误检查就是崩在一个合理的地方

用户错误则用 if-log-return 没有问题

用 std::tuple 和结构化绑定代替一些过分临时的结构体

怎么处理编译期可确定的映射关系

constexpr array(键为或者能够转换为非重复的整数下标)

constexpr / consteval 函数 / Lambda 里的 switch-case

1234auto Lambda = []() constexpr{ //...};