• Google C++ 语言规范


    1. 命名空间

    • KeyNotes:

      • 鼓励在.cc文件里使用匿名命名空间或者sttic声明
      • 禁止使用内联命令空间,X::Y::foo 等价与X::foo。其主要用于跨版本的ABI兼容问题
      namespace X{
      inline namespace Y{
        void foo();
      } // namespace X
      } // namespace Y
      
      • .h头文件使用匿名命名空间违背C++的唯一定义原则(ODR)
    • 使用建议:

      • namespace的结尾}处添加注释

      • 不要在std命名空间中声明任何东西,包括标准库类的前置声明(行为未定义)

      • 禁止使用类似using namespace foo的语句,会导致污染当前命名空间

      • 不要在头文件中使用命名空间别名,除非显示标记内部空间使用。如下是可以的:

        namespace paddle{
        namespace framework{
          using Tensor = paddle::Tensor; // 仅在当前命名空间使用
          
          void foo(){
            using LoDTensor = paddle::LoDTensor; // 限制在一个函数内部使用
          }
        }  // namespace framework
        }  // namespace paddle
        

    2. 匿名命名空间和静态变量

    • KeyNotes:
      • .cc文件中一个变量不需要被外部使用时(内部链接性),可以将其放在匿名空间或者声明为static但不要在.h文件中这么做
      • 内部链接性,意味着此函数、变量不能在另一个文件中被访问。即使两个文件中包含了完全相同的标识符,它们指向的也不一样

    3. 非成员函数、静态成员函数和全局函数

    • KeyNotes:

      • 应尽力避免使用全局函数,取而代之使用静态成员函数,或者命名空间中的非成员函数(避免污染全局作用域)。
      • 定义在同一编译单元中的函数,被其他编译单元调用时,可能会引入不必要的耦合和链接依赖。静态成员函数对此尤其敏感,可以考虑提取到新类中,或置于独立库的命名空间中。
    • 使用建议:

      • 定义非成员函数,且只在.cc文件中使用,使用static关键字修饰,如:

        static void foo(int x){}
        

    4. 静态和全局变量

    • KeyNotes:
      • 编译单元:每一个.c.cc都是一个编译单元
      • 静态生命周期变量:全局变量、静态变量、静态类成员变量和函数静态变量。
      • 同一编译单元内是明确的,静态初始化优先于动态初始化,按声明顺序进行,销毁则反着来。
      • 不同编译单元的构造和析构顺序是未定义的。
    • 使用建议:
      • 禁止定义静态存储周期非POD变量(如int/char/float类型的结构体等)。因为多编译单元下的静态变量执行时的构造和析构顺序是不明确的
      • 函数作用域里的静态变量行为是明确的,因为只会在指令执行声明时才会发生。
      • 若确实需要一个class类型的静态或者全局变量,注意只能使用raw指针别用智能指针,因为后者析构时涉及到上下文指出的不定顺序问题。
      • 当创建静态变量时,请使用C 数组const char[]分别代替 vectorstring

    5. 构造函数

    • 使用建议:
      • 不要在构造函数中调用虚函数,也不要在无法报错时进行可能失败的初始化

    6. 隐式转换

    • 使用建议:
      • 不要定义隐式类型转换。
      • 在转换运算符和单参数构造函数中,请使用explicit关键字。
      • 拷贝和移动构造函数不应当被标记为explicit,因为他们并不执行类型转换。
      • 若一个构造函数包含超过1个参数,不要加explicit关键字(没有意义);例外情况:除了第一个参数外其他参数都有默认值。
      • 接受一个std::initializer_list作为参数的构造器,也应该省去explicit

    7. 可移动与可拷贝

    • KeyNotes:

      • 可移动及可拷贝类型对象支持值传递方式返回,不同于指针,它不会造成所有权、生命周期、可变性等方面的混乱。
    • 使用建议:

      • 不要为基类提供拷贝/赋值操作,因为在使用它们时会造成对象切割
      • 拷贝构造和赋值函数要同时给出或禁用。

    8. 继承:

    • KeyNotes:

      • 继承包括实现继承接口继承:前者子类也继承了父类的实现,后者只继承了接口。
    • 使用建议:

      • 优先使用组合,而非继承。如果使用继承,请使用public
      • 不要过度使用实现继承,组合更合适一些。
      • 若类中包含虚函数,请在析构函数前面加上virtual关键字
      • 在声明重载函数时,请加上override关键字

    9. 接口:

    • KeyNotes:
      • 当一个类满足如下条件时,称之为纯接口
        • 只有纯虚函数(=0)和静态函数
        • 没有非静态成员变量
        • 没有定义构造函数(若有,也不能带参数,且为protected
      • 接口不能被实例化(因为没有可调用的构造函数)

    10. 运算符重载

    • KeyNotes:
      • 重载operator具有诸多弊端,如无必要,应尽量避免。
    • 使用建议:
      • 只有在意义明显,且重载行为与内建运算符一致的情况下,可以考虑重载
      • 若重载了<,请也重载>=

    11. 声明顺序

    • 使用建议:
      • 将相似的声明放在一起。
      • 类的定义一般按照public:protected:private:来组织
      • 并遵循如下顺序:类型(typedefusing和嵌套的类与结构体)、常量、工厂函数、构造函数、赋值运算符、析构函数、其他函数、数据成员。
  • 相关阅读:
    js循环添加事件
    [Swift]LeetCode1085. 最小元素各数位之和 | Sum of Digits in the Minimum Number
    [Swift]LeetCode1089. 复写零 | Duplicate Zeros
    [Swift]冒泡排序 | Bubble sort
    [Algorithm]巧用多项式系数与进制的联系
    [Swift]LeetCode1081. 不同字符的最小子序列 | Smallest Subsequence of Distinct Characters
    [Swift]LeetCode1080. 根到叶路径上的不足节点 | Insufficient Nodes in Root to Leaf Paths
    [Swift]LeetCode1079. 活字印刷 | Letter Tile Possibilities
    [Swift]LeetCode1078. Bigram 分词 | Occurrences After Bigram
    [Swift]快速反向平方根 | Fast inverse square root
  • 原文地址:https://www.cnblogs.com/CocoML/p/14643406.html
Copyright © 2020-2023  润新知