通常如果你使用C part of C++ 而且初始化可能招致运行期成本,那么就不保证发生初始化。一旦进入non-C part ofC ,规则有些变化。这就很好地解释了为什么array (来自C part of C++ )不保证其内容被初始化,而vector (来自STLpart ofC++) 却有此保证。
表面上这似乎是个无法决定的状态,而最佳处理办法就是:永远在使用对象之前先将它初始化。对于无任何成员的内置类型,你必须手工完成此事。例z如int x = 0;const char* text = "A C-style string";double d;
std::cin » d; //以读取input 的方式完成初始化至于内置类型以外的任何其他东西,初始化责任落在构造函数( constructors)身上。规则很简单:确保每一个构造函数都将对象的每一个成员初始化。
这个规则很容易奉行,重要的是别混淆了赋值 和初始化( initialization) 。考虑一个用来表现通讯簿的class ,其构造函数如下:class PhoneNumber { ... };class ABEntry { IIABEntry =叽Address Book Entry"public:ABEntry(const std::string& name, const std::string& address ,const std::list<PhoneNumber>& phones);private:std::string theName;std::string theAddress;std::list<PhoneNumber> thePhones;int numTimesConsulted;ABEntry: :ABEntry(const std: :string& n缸ne , const std: : string& address,const std::list<PhoneNumber>& phones)theName 二口arne; //这些都是赋值(assignments) ,theAddress = address; //始化(initializations)。thePhones = phones;numTimesConsulted = 0;
这会导致ABEntry 对象带有你期望(你指定)的值,但不是最佳做法。C++ 规定,对象的成员变量的初始化动作发生在进入构造函数本体之前。在ABEntry 构造函数内, theNarr吼theAddress 和thePhones 都不是被初始化,而是被赋值。初始化的发生时间更早,发生于这些成员的default 构造函数被自动调用之时(比进入ABEntry 构造函数本体的时间更早)。但这对numTimesConsu1ted 不为真,因为它属于内置类型,不保证一定在你所看到的那个赋值动作的时间点之前获得初值。
ABEntry 构造函数的一个较佳写法是,使用所谓的member initialization list (成员初值列〉替换赋值动作:ABEntry: :ABEntry(const std: :string& n缸ne , const std: :string& address,const std::1ist<PhoneNumber>& phones):theNarne(narne) ,theAddress(address) , //现在,这些都是初始化(initializations )thePhones(phones) ,numTimesConsu1ted(O)( } //现在,构造函数本体不必有任何动作
这个构造函数和上一个的最终结果相同,但通常效率较高。基于赋值的那个版本(本例第一版本)首先调用default 构造函数为theNarne, theAddress 和thePhones设初值,然后立刻再对它们赋予新值。default 构造函数的一切作为因此浪费了。成员初值列(member initialization list) 的做法(本例第二版本)避免了这一问题,因为初值列中针对各个成员变量而设的实参,被拿去作为各成员变量之构造函数的实参。本例中的theNarne 以name为初值进行copy构造, theAddress 以address 为初值进行copy构造, thePhones 以phones 为初值进行copy构造。
规则:规定总是在初值列中列出所有成员变量,以免还得记住哪些成员变量(如果它们在初值列中被遗漏的话〉可以无需初值。