1. 圈复杂度

圈复杂度V(G),也成为条件复杂度,是一种衡量代码复杂度的标准,圈复杂度可以用来衡量一个模块判定结构的复杂程度。

1.1 圈复杂度的标准

一般来说,圈复杂度大于10的方法存在很大的出错风险。小于10代表代码清晰、结构化,可测性高,维护成本低。

1.2 圈复杂度计算方法

  1. 点边计算法
    • 圈复杂度由程序的控制流图来计算。
    • 正常顺序的圈复杂度为1;if else 的圈复杂度为2;while 的圈复杂度也为2。
  2. 节点判定法
    • 圈复杂度 = 判定节点的数量 + 1
    • V(G) = P + 1
    • 常见的判定节点{ if, while, for, case, catch, and, or, ?: }

1.3 Eample 计算圈复杂度

V(G) = 14

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
U32 find (string match){
for(auto var : list) // +1
{
if(var == match && from != INVALID_U32) return INVALID_U32; // +2
}
//match step1
if(session == getName() && key == getKey()) // +2
{
for (auto& kv : Map) // +1
{
if (kv.second == last && match == kv.first) // +2
{
return last;
}
}
}
//match step2
auto var = Map.find(match);
if(var != Map.end()&& (from != var->second)) return var->second; // +2

//match step3
for(auto var: Map) // +1
{
if((var.first, match) && from != var.second) // +2
{
return var.second;
}
}
return INVALID_U32;
};

1.4 降低圈复杂度的方法

  1. 提炼函数:将可以被组织在一起的代码放进独立函数,并让函数名称解释该函数的用途。
  2. 替换算法
  3. 逆向表达
  4. 分解条件
  5. 合并条件
  6. 移除控制标记
  7. 以多态取代条件式
  8. 读写分离
  9. 参数化方法
  10. 以明确函数取代参数

2. Google编码规范

2.1 命名约定

2.1.1 文件命名

  • 文件名全部小写
  • 可以包含 下划线(_)连字符(-)
  • 无特殊要求**下划线(_)**更好
  • C++文件需要以.cc结尾
  • 头文件以.h结尾

Example

1
2
3
4
my_useful_class.cc
my-useful-class.cc
myusefulclass.cc
myusefulclass_test.cc

2.1.2 类型命名

  • 类型名称每个单词首字母大写

Example

1
2
3
4
5
6
7
8
9
10
// 类和结构体
class UrlTable { ...
class UrlTableTester { ...
struct UrlTableProperties { ...

// 类型定义
typedef hash_map<UrlTableProperties *, string> PropertiesMap;

// 枚举
enum UrlTableErrors { ...

2.1.3 变量命名

  • 变量和数据成员名一律小写
  • 单词之间使用下划线连接
  1. 普通变量
    Example

    1
    2
    string table_name;
    string tablename;
  2. 类数据成员
    Example

    1
    2
    3
    4
    5
    6
    7
    class TableInfo {
    ...
    private:
    string table_name_;
    string tablename_;
    static Pool<TableInfo>* pool_;
    };
  3. 结构体变量
    Example

    1
    2
    3
    4
    5
    struct UrlTableProperties {
    string name;
    int num_entries;
    static Pool<UrlTableProperties>* pool;
    };
  4. 常量命名

  • k开头
  • 大小写混合

Example

1
2
3
4
5
struct UrlTableProperties {
string name;
int num_entries;
static Pool<UrlTableProperties>* pool;
};
  1. 函数命名
  • 常规函数大小写混合
  • 取值设值函数与变量名匹配
  • 函数名的每个单词首字母大写
  • 首字符缩写的单词视作一个单词

Example

1
2
3
4
5
MyExcitingFunction()
MyExcitingMethod()
my_exciting_member_variable()
set_my_exciting_member_variable()
StartRpc()
  1. 命名空间命名
  • 命名空间以小写字母命名

2.2 头文件

2.2.1 #define防护符

  • 所有的文件都应该用 #define防护符防止重复导入

Example
对于foo/src/bar/baz.h文件

1
2
3
4
#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
...
#endif // FOO_BAR_BAZ_H_

2.2.2 #include 的路径及顺序

  • 按照以下顺序导入头文件
    1. 配套的头文件
    2. C 语言系统库头文件
    3. C++ 标准库头文件
    4. 其他库的头文件
    5. 本项目的头文件

Example

1
2
3
4
5
6
7
8
9
10
11
#include "foo/server/fooserver.h" // 配套的头文件

#include <sys/types.h> // C 语言系统库头文件
#include <unistd.h>

#include <string> // C++ 标准库头文件
#include <vector>

#include "base/basictypes.h" //本项目的头文件
#include "foo/server/bar.h"
#include "third_party/absl/flags/flag.h"

参考

https://kaelzhang81.github.io/2017/06/18/%E8%AF%A6%E8%A7%A3%E5%9C%88%E5%A4%8D%E6%9D%82%E5%BA%A6/