条款04:确定对象被使用前已先被初始化
读取未初始化的值会导致不明确的行为。对于无任何成员的内置类型,必须完成手工初始化任务。至于内置类型以外的任何其他东西,初始化责任落在构造函数身上。确保每一个构造函数都将对象的每一个成员初始化。重要的是别混淆了赋值和初始化:
ABEntry::ABEntry(const std::string & name, const std::string& address, const std::list<PhoneNumber>& phones)
{
theName = name; //这些都是为成员赋值(assignments),
theAddress = address; //而非初始化(initializations)。
thePhones = phones;
numtimesConsulted = 0;
}
C++规定,对象的成员变量的初始化动作发生在进入构造函数的本体之前。在ABEntry构造函数内,成员变量都不是被初始化,而是被赋值。真的初始化会在这些成员的default构造函数被自动调用之时(比进入ABEntry构造函数本体的时间更早)。构造函数的一个较好的写法是,使用所谓的成员初值列替换赋值动作:
ABEntry::ABEntry(const string& name, const string& address, const list<PhoneNumber>& phones)
:theName(name),
theAddress(address),
thePhones(phones),
numtimesConsulted(0)
{} //构造函数本体不再做赋值动作
值得注意的是,内置类型初始化与赋值的成本相同,但也一定的使用初值列。但是当成员变量较多时,此时可对内置类型的变量进行赋值动作,并集中写在某private函数中,以供其他构造函数使用。
C++有着十分固定的“成员初始化次序”。基类早于子类,先声明的成员变量早于后声明的变量。
请记住
- 为内置对象进行手工初始化,因为C++不保证初始化他们。
- 构造函数最好使用成员初值列,而不要在函数体内使用赋值动作,并且初值列的成员变量的排列次序应该和他们在类中的声明次序相同。
- 为免除“跨编译单元之初始化次序”问题,请以local static对象替换non-local static对象。前提是在单线程程序中。