Google Coding Style学习笔记
来源: Google Coding Style Guide 中文版
笔记:
1、
#define 保护
所有头文件都应该使用 #define
来防止头文件被多重包含, 命名格式当是: <PROJECT>_<PATH>_<FILE>_H_
.
为保证唯一性, 头文件的命名应该基于所在项目源代码树的全路径. 例如, 项目 foo
中的头文件 foo/src/bar/baz.h
可按如下方式保护:
#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
…
#endif // FOO_BAR_BAZ_H_
2、
内联函数
Tip
只有当函数只有 10 行甚至更少时才将其定义为内联函数.
3、
#include
的路径及顺序
Tip
使用标准的头文件包含顺序可增强可读性, 避免隐藏依赖: 相关头文件, C 库, C++ 库, 其他库的 .h, 本项目内的 .h.
- 避免多重包含是学编程时最基本的要求;
- 在
#include
中插入空行以分割相关头文件, C 库, C++ 库, 其他库的.h
和本项目内的.h
是个好习惯。
4、
结构体 VS. 类
Tip
仅当只有数据时使用 struct, 其它一概使用 class.
5、
运算符重载
Tip
除少数特定环境外,不要重载运算符.
6、
引用参数
Tip
所有按引用传递的参数必须加上 const
.
7、
变长数组和 alloca()
Tip
我们不允许使用变长数组和 alloca()
.
优点:
变长数组具有浑然天成的语法. 变长数组和alloca()
也都很高效.
缺点:
变长数组和alloca()
不是标准 C++ 的组成部分. 更重要的是, 它们根据数据大小动态分配堆栈内存, 会引起难以发现的内存越界 bugs: “在我的机器上运行的好好的, 发布后却莫名其妙的挂掉了”.
结论:
改用更安全的分配器(allocator),就像std::vector
或std::unique_ptr<T[]>
.
8、
异常
Tip
我们不使用 C++ 异常.
9、
类型转换
Tip
使用 C++ 的类型转换, 如 static_cast<>()
. 不要使用 int y = (int)x
或 int y = int(x)
等转换方式;
10、
前置自增和自减
Tip
对于迭代器和其他模板对象使用前缀形式 (++i
) 的自增, 自减运算符.
定义:
对于变量在自增 (++i
或i++
) 或自减 (--i
或i--
) 后表达式的值又没有没用到的情况下, 需要确定到底是使用前置还是后置的自增 (自减).
优点:
不考虑返回值的话, 前置自增 (++i
) 通常要比后置自增 (i++
) 效率更高. 因为后置自增 (或自减) 需要对表达式的值i
进行一次拷贝. 如果i
是迭代器或其他非数值类型, 拷贝的代价是比较大的. 既然两种自增方式实现的功能一样, 为什么不总是使用前置自增呢?
缺点:
在 C 开发中, 当表达式的值未被使用时, 传统的做法是使用后置自增, 特别是在for
循环中. 有些人觉得后置自增更加易懂, 因为这很像自然语言, 主语 (i
) 在谓语动词 (++
) 前.
结论:
对简单数值 (非对象), 两种都无所谓. 对迭代器和模板类型, 使用前置自增 (自减).
11、
const
用法
Tip
我们强烈建议你在任何可能的情况下都要使用 const
. 此外有时改用 C++11 推出的 constexpr 更好。
12、
预处理宏
Tip
使用宏时要非常谨慎, 尽量以内联函数, 枚举和常量代替之.
13、
0, nullptr
和 NULL
Tip
整数用 0
, 实数用 0.0
, 指针用 nullptr
或 NULL
, 字符 (串) 用 '\0'
.
整数用 0
, 实数用 0.0
, 这一点是毫无争议的.
对于指针 (地址值), 到底是用 0
, NULL
还是 nullptr
. C++11 项目用 nullptr
; C++03 项目则用 NULL
, 毕竟它看起来像指针。实际上,一些 C++ 编译器对 NULL
的定义比较特殊,可以输出有用的警告,特别是 sizeof(NULL)
就和 sizeof(0)
不一样。
字符 (串) 用 '\0'
, 不仅类型正确而且可读性好.
14、
通用命名规则
Tip
函数命名,变量命名,文件命名要有描述性;少用缩写。
尽可能给有描述性的命名,别心疼空间,毕竟让代码易于新读者理解很重要。不要用只有项目开发者能理解的缩写,也不要通过砍掉几个字母来缩写单词。
15、
文件命名
Tip
文件名要全部小写, 可以包含下划线 (_
) 或连字符 (-
). 按项目约定来. 如果并没有项目约定,”_” 更好。
可接受的文件命名:
* my_useful_class.cc
* my-useful-class.cc
* myusefulclass.cc
* muusefulclass_test.cc // ``_unittest`` 和 ``_regtest`` 已弃用。
16、
类型命名
Tip
类型名称的每个单词首字母均大写, 不包含下划线: MyExcitingClass
, MyExcitingEnum
.
17、
变量命名
Tip
变量名一律小写, 单词之间用下划线连接. 类的成员变量以下划线结尾, 但结构体的就不用,如:: a_local_variable
, a_struct_data_member
, a_class_data_member_
.
18、
常量命名
Tip
在全局或类里的常量名称前加 k
: kDaysInAWeek. 且除去开头的 k
之外每个单词开头字母均大写。
所有编译时常量, 无论是局部的, 全局的还是类中的, 和其他变量稍微区别一下. k
后接大写字母开头的单词:
const int kDaysInAWeek = 7;
这规则适用于编译时的局部作用域常量,不过要按变量规则来命名也可以。
19、
函数命名
Tip
常规函数使用大小写混合, 取值和设值函数则要求与变量名匹配: MyExcitingFunction()
, MyExcitingMethod()
, my_exciting_member_variable()
, set_my_exciting_member_variable()
.
20、
文件注释
Tip
在每一个文件开头加入版权公告, 然后是文件内容描述.
法律公告和作者信息:
每个文件都应该包含以下项, 依次是:
- 版权声明 (比如,
Copyright 2008 Google Inc.
)- 许可证. 为项目选择合适的许可证版本 (比如, Apache 2.0, BSD, LGPL, GPL)
- 作者: 标识文件的原始作者.
21、
类注释
Tip
每个类的定义都要附带一份注释, 描述类的功能和用法.
// Iterates over the contents of a GargantuanTable. Sample usage:
// GargantuanTable_Iterator* iter = table->NewIterator();
// for (iter->Seek("foo"); !iter->done(); iter->Next()) {
// process(iter->key(), iter->value());
// }
// delete iter;
class GargantuanTable_Iterator {
...
};
22、
行长度
Tip
每一行代码字符数不超过 80.
23、
函数声明与定义
Tip
返回类型和函数名在同一行, 参数也尽量放在同一行,如果放不下就对形参分行。
24、
类格式
Tip
访问控制块的声明依次序是 public:
, protected:
, private:
, 每次缩进 1 个空格.