0%

google_c++编程风格指南

指南简介

谷歌开源项目主要是C++,因此开放编程指南方面合并代码,总共五万字指南涉及广泛,论证严密。指南不仅列出怎么做以及为什么这么做,同时告诫什么情况可以破例以及权衡其中利弊。

背景

由于C++强大的特性,容易产生难以阅读和维护的问题,有时候需要限制部分特性以保持代码清爽。

头文件

头文件:每个.cc对应一个.h,main和单元测试除外

自给自足原则(self-contained):一个头需要包含自身所需的其他头,同时使用#define保护;若非如此,头需要特定平台的symbols则用.inc扩展名。

所有头应使用#define防止多重包含,保证唯一性。

使用前置声明

先声明,后面再定义。

优点:

  • 节省编译时间,多余#include迫使编译器展开文件,处理更多输入
  • 节省重新编译时间,#include使代码因头文件无关改动而重新编译多次

缺点:

  • 隐藏了依赖关系,头文件改动时跳过必要的重新编译过程
  • 可能被库的后续更改所破坏
  • 声明来自std::的symbol,其行为未定义
  • 难以判断何时使用前置声明还是#include,极端情况甚至暗暗改变代码含义

总结:

  • 尽量避免前置声明那些定义在其他项目中的实体
  • 函数:总是使用#include
  • 类模板:优先使用#include

内联函数

只有10行以内才定义内联,直接代码展开

优点:目标代码高效,关键函数可内联
缺点:滥用会使代码量增大
总结:

  • 谨慎对待析构函数内联,隐含的成员和基类析构会被调用
  • 内联包含循环或switch语句的函数常常得不偿失
  • 编译器不会把虚函数和递归函数内联

#include路径及顺序

项目内头文件应按项目源码目录树结构排列,避免使用UNIX特殊的快捷目录.或..
e.g. #include “dir2/foo2.h”头文件的次序:

  • 1.dir2/foo2.h
  • 2.C系统文件
  • 3.C++系统文件
  • 4.其他库的.h文件
  • 5.本项目内的.h文件

条件编译

1
2
3
#ifdef LANG_CXX11
#include <initializaer_list>
#endif

译者笔记:

  • 避免多重包含是最基本的要求
  • 前置声明是为了降低编译依赖,防止修改文件头引起多米诺效应
  • 内联函数合理使用可提高代码效率
  • 独立内联头-inl.h可提高代码可读性
  • 使用完整项目路径可减少隐藏依赖,保证内部错误及时发现
  • 前置声明的类为不完全类型,只能定义指向的指针或引用
  • 类内部函数自动内联,建议独立放入.cc文件,贯彻声明与定义分离原则
  • #include中插入空行以分离头文件,C库,C++库以及其他库.h和本项目.h

作用域

命名空间将全局作用域细分为独立作用域,可有效防止全局命名冲突
内联命名inline namespace只允许用于跨版本的ABI兼容性

默认命名空间:main存在的常用的,其他空间调用可::func
匿名空间:无名namespace{},主要用途:1.定义符号限于文件内部使用,不被外部引用 2.类似static修饰整个空间内容

关于使用命名空间的策略标准:

  • 允许鼓励匿名命名空间,避免运行时命名冲突
  • 不在std空间声明任何东西,会引起不可移植性
  • 尽量不用using namespace name;污染命名空间
  • 允许使用空间别名
  • 禁止内联命名空间

嵌套类

即成员类用法
缺点:嵌套类只能在外围类的内部做前置声明,即任何使用Foo::Bar*的指针头文件必须包含Foo的整个声明。
用法:不要定义为公有,除非是接口的一部分。