减少编程错误
安全编码与未定义行为
表达式与变量
函数与类
安全编码与未定义行为
1.不能使用超出边界的指针或者数组下标(缓冲区溢出)
2.不能返回指向局部变量的指针,悬空指针
3.整形运算时确保有符号数的运算不溢出
4 类型转换导致溢出问题
表示数值用signed char 或unsigned char
无符号数与有符号数不能混用 不得不用时 显示指定类型转换
原因:(有符号)char在转换成unsigned int有两种路径
char int unsigned int
char unsigned char unsigned char不同编译器结果不同 避免这种不确定行为
造成的后果:很严重 隐私泄露 黑客入侵
表达式与变量
1.全局变量初始化
两个cpp文件中全局变量的初始化顺序不同 避免不同cpp文件中全局变量的初始化产生依赖关系
改进:static变量
2.if语句 判断条件写错误
if for while 的判断条件不应为恒定值 工具可检查出
3. switch语句
每个分支case通常都要有一个break或return 确实要进行滑入下一条语句时明确注释或使用c++17的fallthrough
4.i++或i–
在含有变量自增或子减运算的表达式中禁止再次引入该变量
避免这种写法 func(i++,i)
5.局部变量
局部变量大小超过1k,就要审视合理性。过大的局部变量,有栈溢出的风险
较大的类型作为函数参数时,应该使用引用或const 引用,减少拷贝
6.使用引用取代指针
引用不为空,而且指向的对象不会变化。应当优先使用引用取代指针
7.不修改变量或函数使用const修饰
定义接口时 将不修改的类型声明为const 可以让使用者知道哪些对象不会被修改
如果编码时不慎将对象修改了,能够在编译时发现问题而不是等到运行时debug
8.数组作为参数
不要将指针作为sizeof的参数来获取指向内容的长度 此时获取的是指针的大小
不要对函数的数组参数使用sizeof 因为函数的数组参数实际是指针
函数与类
1.设计函数时,应当优先使用函数返回值而不是输出参数
2.避免使用宏
宏有类型检查 非预期副作用 运算优先级等各方面的缺点,应该尽可能使用函数 inline函数 模板函数代替宏
不得不使用宏时 应当在定义宏时使用完备的括号
3.类成员变量初始化
禁止使用未初始化的变量作为右值
类的所有构造函数都要保证所有成员被正确初始化 可以使用初始化列表或类内初始化来初始化成员
4.虚函数的重写规则
在重写虚函数时使用override或final关键字
避免重写时父类与子类函数不一致
5.禁止在构造函数和析构函数中调用虚函数
父类构造函数中调用虚函数 此时虚表还没有初始化完成 不会调用到子类的虚函数 而是父类的虚函数 若此时父类的虚函数是纯虚函数则会产生未定义行为。
6.禁止使用memcpy memset 等内存操作函数初始化非pod对象
7.基类的析构函数应当声明为虚函数
当通过基类的指针析构时 不会调用到子类的析构函数 可能导致内存泄露
8.禁止父类的虚函数定义与子类不同的缺省参数
通过基类的指针调用虚函数时 因为调用的函数是运行时决定的,所以此时调用的是子类的虚函数,但缺省参数是编译时决定的,那么编译时期的指针类型确定缺省参数的值是多少,因为指针类型是基类,所以最后调用的是子类的虚函数但缺省参数却是父类的。
9.避免使用void*
void*丢失了对象的类型信息,失去了编译时的类型检查能力,应该避免使用。