条款04:确定对象被使用前已先被初始化
读取未初始化的值会导致程序发生不明确的行为。对于内置类型以外的其他任何类型,初始化的责任落在了构造函数身上。
在落实这个规则的时候要注意,不要混淆了赋值和初始化 。
class ca{ int a; }; class cb{ int a; string b; vector<ca> c; cb(const int& aa,const string& bb,const vector<ca> cc){ a=aa; //这些都是赋值! b=bb; //而不是初始化! c=cc; } };
对于上面的程序,并不是高效率的做法,在构造函数内,变量都不是被初始化,而是被赋值(内置类型除外)。这意味着,首先调用默认的构造函数来为bb,cc设初值,然后再立刻为他们赋值。默认构造函数所做的工作就被浪费了。
一种更好的写法是使用成员初值列,代码如下
class cb{ int a; string b; vector<ca> c; cb(const int& aa,const string& bb,const vector<ca> cc): a(aa), b(bb), c(cc){} };
对于大多数类型而言,比起现调用default构造函数再调用赋值操作符,单调用一次copy构造函数是更高效的。
请立下一个规则,规定总是在初值列中列出所有的成员变量,以避免某些变量未被初始化。
有些情况下,即使面对的成员变量是内置类型,也必须要用初值列,而不能被赋值(例如const变量和引用变量)。
class内变量初始化的顺序总是和他们在类内声明的顺序是相同的。为了方便阅读,在成员初值列中列出各个成员时,总是按照其声明的次序为次序。
请以local static代替non-local static。
例如我们在文件1中定义 int a = 1;
我们在文件2中定义 extern int a;int b = a*3;
如果文件2在文件1之前被调用,那么b值就有可能是垃圾值。为了避免这种问题,我们应该避免使变量具有全局的作用域 ,具体的做法就是以local static来代替non-local static,代码如下
int& getA(){ //文件1中 static int a = 1; return a; } int b = getA()*3;//文件2中
这样做就能保证a的初始化在前了