公司C++规范学习

公司C++规范学习

语法部分

  • class和struct关键字的选择:class表示被封装的用户自定义类型,不公开定义非静态数据成员,struct表示数据的简单集合,只定义用于初始化数据成员的方法。
  • 必须使用构造函数初始化列表显示初始化直接基类与全部基类类型数据成员。
  • 没有复制意义的类必须用DISALLOW_COPY_AND_ASSIGN宏禁止拷贝构造函数和赋值构造函数。
    • DISALLOW_COPY_AND_ASSIGN 宏就是将复制拷贝函数和赋值操做符声明为私有变量。
  • 禁止在构造函数中进行可能出错的复杂操做(好比申请资源),复杂操做用额外的init()函数实现。
  • 显式初始化可以使代码更清晰、不易错误调用,还能避免二次赋值形成的效率问题, 单参构造函数尽可能加上explicit。
  • 有默认值语义的类必须显示定义默认构造函数。
  • 没有默认值语意的类,必须显式定义其它构造函数或 private 声明默认构造函数,并不给出实现。
  • 若是类型是可拷贝,必定要同时定义拷贝构造函数和赋值构造函数,若是类型可移动,必定要同时定义移动构造函数和移动赋值函数。
    • 若是使用默认的拷贝和移动操做,要使用=default定义。
    • 若是类型不须要拷贝、移动操做,要使用=delete手段禁用。
    • 向容器添加数据时,优先使用emplace开头的接口函数。
  • 在极少的状况下,当该类的隐式转换颇有意义时,能够不把单参数构造函数声明为显式构造函数,但必须十分当心,并使用文档化注释说明。
  • 单参数构造函数若是不用explicit关键字修饰,则可能被编译器用来作隐式类型转换。
  • 有复制意义的类必须显式给出复制构造函数,并当心指定其行为(浅复制、深复制等)
    • 托管了资源的类,每每是没有复制意义的。此时应当防止用户错误调用而致使资源泄漏、重复释放的后果。
    • 编译器默认生成的复制构造函数,对指针数据成员使用浅复制策略,但这种策略经常不是程序员但愿的。
  • 析构函数:
    • 若类定义了虚函数,必须定义虚析构函数。
    • 若类设计为可被继承的,应该定义公开的虚析构函数或保护的非虚析构函数。
    • [RULE010] (不包括结构)含有指针成员,必须显式给出析构函数,并当心指定其行为(是否销毁指针,如何销毁等).
    • 毫不容许让异常离开析构函数。
  • 按照 public、protected、private 的顺序声明成员。按照类型、方法、数据成员的顺序声明成员, DISALLOW_COPY_AND_ASSIGN 放在 private 区段的末尾.
  • 不是很是必要的话,避免使用友元: 友元破坏了类的封装性,增长了类之间的耦合,适宜使用友元的如容器与它的迭代器,类与涉及该类的.
  • 委派和继承构造函数是由 C++11 引进为了减小构造函数重复代码而开发的两种不一样的特性. 经过特殊的初始化列表语法, 委派构造函数容许类的一个构造函数调用其余的构造函数.
  • C++11强类型枚举enum class Side
  • 被重载的虚函数经过override显示声明.
  • 禁止被重载的函数经过final显示禁止.
  • Lambda表达式:
    • 不使用默认捕获(包括&, =), 捕获显示写出来.
  • 只在两种状况下使用右值引用, 一种是定义类型的移动操做函数时, 另外一种是定义模板函数实现完美转发的时候. 除此以外, 不要使用右值引用.
    • 右值引用的语义比较复杂, 不恰当的使用会形成很难追查的bug.
  • 建议 include 的路径、文件名与命名空间保持一致
  • 使用空格缩进,不使用制表符。 以 4 个空格为单位缩进。避免超过 5 重的缩进。
  • 建议不要使用异常,除非已有项目/底层库使用了异常, 这时候必需要catch全部异常。
  • 全部代码应该定义在namespace中, main函数除外。
  • 禁止内联(inline)虚函数,inline函数应该在10行之内。
  • 函数静止使用默认参数,模板可使用默认参数。-- 默认参数是编译期绑定的,不具备多态性。
  • 使用 auto 自动推导类型, 只能定义局部变量(返回类型后置声明除外).
  • 禁止使用 auto_ptr. 若是须要传递对象, 使用std::unique_ptr明确全部权传递. 若是要共享全部权, 使用std::shared_ptr明确全部权共享.
  • [RULE033] 避免对浮点数进行相等或不等比较。
    • 避免使用非布尔型的变量或表达式做为分支语句条件。
    • 做相等比较时,建议把常量或右值变量放在 == 运算符的右边。
  • 除非用于条件编译、跟踪调试,或者可以显著减小代码量并确保可读性的宏(如 DISALLOW_COPY_AND_ASSIGN, CFATAL_LOG etc.),不然不该使用。
  • 鼓励使用前向声明,以减小文件之间的依赖关系。
  • 尽量避免使用全局变量,若有必要应使用 singleton 模式代替。
    • 内部使用的全局函数/变量,必须声明为静态函数、变量,不能在目标文件中出现外部可见的符号。
  • 不该在头文件定义类/结构体类型的全局常量,以减小代码膨胀。
  • 可能用于跨模块间通信或者涉及存储的枚举值必须显式指定值,避免版本不一致形成诡异的错误。
  • const 关键字用在类型名前面而非后面。
    • 不修改内部状态的成员方法必须声明为 const
    • 返回不可修改的指针或引用必须声明为 const
    • 不被修改的引用/指针形参必须声明为 const
    • 除非保证状态不会被修改,不该使用 const_cast 来去掉 const 属性
  • 避免定义超过 4 KB 的局部变量数组

风格/约定

  • 必须按如下顺序引用头文件,并进行分节:.cpp 对应的头文件(若是有, // 优先位置), C(标准)库,C++(标准)库,其它库,本身项目的.h文件,每节内的include按照字母序。
  • 分行与空格:
    • 一条单独的语句必须独立成行。
    • 避免连续的空行。
    • 使用适当的空行来分组代码的逻辑。
    • 左大括号不独立,右大括号独立成行。而且左大括号所在行进行垂直对齐。
  • 命名空间不缩进。
  • 构造函数初始化列表放在同一行或按至少八格缩进并排几行, 若是须要换行, 把: 放在第一行。
  • 比较短的函数声明,整个声明占一行;过长的函数声明,令每一参数占一行,而且垂直对齐, 换行后的参数至少保持 8 个空格缩进。
  • 比较短的函数调用语句,整个语句占一行;过长的函数调用,控制折行确保每行不要超过 100 列,换行后至少额外缩进 8 个空格。
  • 空格的使用:
    • if/switch/while/for/catch 与后边的圆括号之间加一个空格,圆括号内侧与判断表达式之间不加空格。
    • for语句圆括号内分号前不加空格,分号后加一个空格。
    • 函数调用中,函数名和圆括号之间不要加空格。
    • 类继承与构造函数的初始化列表的冒号先后加一个空格。
    • 逗号表达式或参数列表中,逗号前不加空格,逗号后加一个空格。
    • 一元运算符先后不加空格。二元、三元表达式先后各加一个空格。
    • 成员访问或做用域运算符先后不加空格。如:a.b, a->b, a.b, a->b, a::b。
    • 圆括号和方括号运算符先后和内部都不加空格。
  • .h 中不要定义复杂的函数, 复杂函数若是必须在头文件中, 应该放在 .hpp 后缀的头文件中。
  • 没有使用到的函数参数,把参数名注释起来, 不容许未命名参数出现。
    • :函数的参数顺序,建议先安排输入参数,再安排输出参数。
    // 输入参数对象类型使用const引用
    void foo(const std::string& input1, const MyClass& input2);

命名规范

  • 全局可见的,却又没法经过命名空间约束的标识符命名,必须以库名做为前缀,以免冲突。
  • 命名应当尽量有描述性,不使用非通用的缩写(尤为是省一个字符的缩写如creat,usr等),不使用有歧义的缩写,不使用任意的无心义的字符.
  • 标识符的做用域越大,命名就应该越清晰。
  • 可能使用多个单位名称的变量(如表示时间的变量),应以单位名称缩写为后缀。
  • 文件名所有用小写字母, 中间用_间隔; 好比: this_is_my_awesome_file.cpp.
  • 单元测试文件名使用 <被测文件名> _test.h(.cpp)命名.
  • 若是是要发布供它人使用的 lib,推荐仅暴露一个以库名同名,或者 <库名> _ <功能集合> .h的 api 头文件,而后将相关头文件 include 到这个 api 头文件中。如:mylib.h,mylib_utils.h,mylib_api.h。
  • 使用下划线分隔的全小写命名法命名命名空间。
  • 命名空间名可使用缩写,同时应保证简短、不易冲突但同时富有意义。
  • 函数命名使用下划线分隔的全小写命名法。
  • 函数一般使用动词短语命名。
  • 自定义类类型使用首字母大写的驼峰命名法命名,通常不使用前缀。
  • 枚举类型成员,使用全大写蛇形命名法(即所有字母大写,单词间用下划线分隔)。
  • 尽量不使用全局变量,若是必须使用,必须以g为前缀,并且必须足够长以免名字冲突。
  • 全局变量使用下划线分隔的全小写命名法命名。
  • 局部变量名使用下划线分隔的全小写命名法命名。
    • 假如局部变量做用域很小,能够适当使用缩写。
  • 全局静态变量 s_ 做为前缀。类静态成员使用 s 前缀的下划线分隔的全小写命名法命名。
  • const 常量与枚举常量都使用下划线分隔的全大写命名法命名
  • 肯定须要不一样大小的变量,推荐使用<stdint.h>中定义的长度明确的整形类型,例如 int64_t, int32_t 等。
  • 多行注释必须写在被解释内容的上方。单行注释能够写在被注释语句的上文或右方。api

  • 一行内只应声明一个变量。
  • 局部变量应尽可能延迟到第一次使用处声明。
  • 局部变量应在声明处赋初值,指针类型局部变量必须在声明处赋初值。
  • 本规范不适用于引入的公司外第三方代码, 修改时请遵照第三方代码自身的编码风格。
  • 显式或者经过宏等隐式的定义派生自第三方代码中所申明的类,必须遵照对应第三方代码自身的编码风格。数组

相关文章
相关标签/搜索