Effective C++学记之04 确定对象被使用前先被初始化

来源:互联网 发布:刷年费会员软件 编辑:程序博客网 时间:2024/06/06 05:55
1 对内置类型进行手工初始化,因为c++不保证初始化它们。
内置类型:int x = 0; //手工实现初始化

通常如果使用c part of c++而且初始化可能招致运行期成本,就不保证发生初始化;
一旦进入non-c part of c++,规则有些变化。这就很好的解释了为甚array(来自c part of c++)不保证其内容初始化,而vector(来自non-c part of c++)却有次保证。

2 构造函数最好使用成员初值列,而不要在构造函数本体内使用复制操作。初值列列出的成员变量,其排列次序应该和他们在class中的声明次序相同。

看下面这个例子:

class ADEntry{
public:
    ABEntry(const std:string& name);
private:
    std::string theName;
};
ABEntry::ABEntry(const std:string& name)
{
    theName = name;//这是赋值,不是初始化!!
}
c++规定,对象的成员变量的初始化动作发生在进入构造函数本体之前。也就是各个成员的default构造函数被自动调用之时(内置类型除外)。以上代码首先调用default构造函数为theName设初值,然后立即再对theName赋予新值。default构造函数的一切作为因此浪费了。

更高效的写法:使用成员初值列(member initialization  list)替换赋值动作。如下:
ABEntry::ABEntry(const std::string& name):theName(name){//构造函数内不必有任何操作}

初值列中针对各个成员变量设置的实参,被拿去作为各成员变量之构造函数的实参。本例中theName以name为初值进行copy构造。

对于大多数类型而言,比起先调用default构造函数再调用copy赋值操作符,只调一次copy构造函数是比较高效的;对于内置对象,其初始化和赋值的成本相同,但为了一致性最好也通过成员初值列来初始化。


BAEntry::BAEntry():theName(),    //调用theName的default构造函数
           numTimesConsulted(0) //将numTimesConsulted显式初始化为0
{}

规则:总是在初值列中列出所有成员变量,以免还得记住哪些成员变量可以无需初值。
注意:如果成员变量是const或者引用,必须初始化,不能被赋值。(条款5)
对于拥有多个构造函数的class且存在多个成员变量或base class,可以合理地在初值列遗漏哪些“赋值表现像初始化一样好”的成员变量。

3 为免除“跨编译单元之初始化次序”问题,请以local static对象替换non-local static对象。

这里说的local static对象指的是函数内的static对象。相应的其他static对象就被称为non-local static对象。
所谓编译单元是说产出单一目标文件的源码(源码文件+头文件 #include files)。
由于c++对“不同编译单元内定义之non-local static对象”的初始化次序没有明确定义。
如果某编译单元内的某个non-local static对象的初始化操作使用了另一个编译单元内的某个non-local static对象,这个对象可能尚未被初始化。

解决的办法就是:将non-local static对象变为local static对象。将每个non-local static函数搬到自己的专属函数内(该对象在此函数内被声明为static),这些函数返回一个引用指向它所含的对象。然后调用这个函数,而不直接指涉这些对象。
(例:单例模式的实现)