C++实用经验(二)
声明:以下内容总结自《C++程序员不可不知的101条实用经验》
尽可能多地使用const
函数声明使用const
void func(const int *a) 等价于void func(int const *a)
const在*的左边,则指针所指的对象不可变;const在*的右边,则指针不可变。
函数返回值声明为const
A{}
A operator*(const A &a, const A &b);
A a, b, c
(a * b) = c; //不符合逻辑,通过const A operator*(const A &a, const A &b);防止函数调用表达式不能作为左值
const类成员函数
按位恒定规则:当且仅当一个成员函数对所有的数据成员都不做出改动时,才需要将此函数声明为const。这将使得错误检查更轻松
逻辑恒定规则:一个const成员函数可能对其调用的对象内部做出改动,但仅仅以客户端无法察觉的方式进行,使用mutable数据成员可实现这一目标
尽量用const常量代替#define定义常量
- #define没有类型检查,可能有边际效应。而const有类型检查
- #define定义的常量在内存中有多个拷贝,而const常量只有一份拷贝,所以使用const常量可以节省内存
尽量用new/delete替代malloc/free
- new/delete在管理内存时会调用类的构造函数和析构函数,而malloc/free仅仅实现了内存的分配和释放
- new/delete是运算符,而malloc/free是C语言标准库函数
- 通过new创建的对象具有类型,而malloc返回值类型为void*,需要进行强制类型转换
- new申请内存失败会调用new_handler处理函数,而malloc申请内存失败仅仅返回NULL,不进行其他任何善后处理
- new/delete具备malloc/free的所有功能,还具有更好的安全特性,不要混用new和malloc,尽量使用new
- 调用new时使用了[],则对应调用delete时也使用[]
string *s = new string();
string *sarr = new string[10];
//......
delete s;
delete []sarr;
sizeof和对象大小
用法
- sizeof不是函数,不是一元操作符,像一个特殊的宏,在编译阶段求值
- 任何类型的指针,sizeof结果都是4(32位)或8(64位)
- 函数类型以其返回值的类型作为自身类型,sizeof(func())的值为func()返回值类型大小
- 无法对函数指针使用sizeof
int func();
sizeof(func()); //4
sizeof(func); //error
- 字符数组表示字符串时,末尾会自动加’\0’,所以sizeof时会在字符串中字符个数的基础上加1
- C语言中多维数组的实现是通过一维数组实现的,所以数组的大小是各维度的乘积乘以数组元素大小
- 向函数形参传递数组,数组指针会退化为普通指针,失去原有数组指针的特性
char *a = "abc"; //sizeof(a)为3+1=4
char b[] = {'a', 'b', 'c'}; //sizeof(b)为3
int c[20] = {1,2}; /sizeof(c)为20 * 4=80
char d[2][3] = {"aa", "bb"}; //sizeof(d)为6,sizeof(*d)为3
- 对一个空的结构体或类进行sizeof运算,结果为1,不为0,这是编译器为了保证空结构体和空类存在而专门分配这一个字节
- 类的大小
1)没有继承和static成员的类:需要内存对齐,和结构体大小计算方式一样,空类占用一个字节。类的成员函数为所有类对象共享,存储在代码段,所以不占用对象空间
2)包含继承和static成员变量的类:在单继承的情况下,只要类中有virtual函数,就会有一个指向虚函数表的指针。static成员分配在全局区,为类的所有对象共享,sizeof不考虑静态成员
谨慎使用static
静态局部变量
- 存储在全局静态存储区,在初次运行进行初始化,编译器可自动初始化为0
- 记忆性:前后两次函数调用时,第二次调用进入 时,能保持第一次调用退出时的值。
- 全局性:生存周期与全局变量、程序相同
- 记忆性破坏了程序的不可重复性,导致不同时刻的运行结果可能不同
- static具有全局唯一性,每次调用都指向同一块内存,造成不可重入性
- 局部static变量导致函数具有线程不安全性,即多个线程调用同一函数时,可能出现读取脏数据等情况
静态全局变量
静态全局变量和全局函数不能被其他文件访问的,用于限定作用域
- 静态成员变量
1)遵从public、protected、private访问规则
2)初始化格式:<数据类型> <类名>::<静态成员变量>=<值>
3)多个同类对象共享静态成员变量,在程序中只有一份拷贝 - 静态成员函数
1)没有隐含的this指针,效率比普通函数高
2)不可访问类的非静态成员,只能访问静态成员