条款04:确定对象被使用前已被初始化

请记住:

  • 为内置对象进行手工初始化,C++不保证初始化。
  • 构造函数最好使用 成员初值列 ,而不要在构造函数内使用赋值操作。且成员变量的排列次序与Class中声明的相同
  • 为免除“跨编译单元之初始化次序”问题,请用local static对象替换non-local static对象

准则理解:

  • 用成员初值列替代初始化而不是赋值。
    简单的理解,类数据成员可以是string、vector、list或者其他的类。若使用赋值语句,在进入构造函数函数体进行赋值首先调用这些类的默认构造函数,再使用这些类的复制构造函数进行赋值。而不进入函数体赋值,使用成员初值列进行初始化,实际上是只使用的这些类的构造函数(非默认)。后者效率明显要高一些。

  • 为免除“跨编译单元之初始化次序”问题,请用local static对象替换non-local static对象。
    具体例子:
    文件1:

class FileSys
{
public:
    size_t numDisks() const;
};
extern FileSys tfs;

文件2:

class Diectory
{
public:
   Directory(param);
};
Directory::Directory(param)
{
     size_t disks=tfs.numDisck();
}
Directory tempDir(params);

当文件2用户创建一个Directory 对象temDir时,可能会出现一个问题:temDir的构造函数可能会用到尚未初始化的tfs,除非能保证tfs在tempDir之前初始化。但是tempDir和tfs是不同时间不同人不同源码文件建立起来的,所以肯定不能保证。
考虑将每个non-local static对象搬到自己的专属函数内(声明为static),这些函数返回一个应用指向它所含的对象,然后其他的地方调用这些函数,而不直接指涉这些对象。
文件1:

class FileSys
{
public:
    size_t numDisks() const;
    static FileSys & tfs();  
};
FileSys& FileSys::tfs()
{
    static FileSys fs;   // 定义并初始化一个local static 对象
    return fs;
}

文件2:

class Diectory
{
public:
   Directory(param);
};
Directory::Directory(param)
{
     size_t disks=FileSys::tfs().numDisck();
}
Directory& tempDir()
{
      static Directory td; //定义并初始化local static对象
      return td;
}

这样在文件2中调用tempDir返回我们需要的Directory对象可以保证tfs一定已经初始化,注意默认构造函数中是tfs().numDisck()而不是tfs.numDisck()。

一个更简单的例子:
文件1:

int a = 1;

文件2:

extern int a;
int b = a * 3;

同样的存在问题:文件1和文件2谁在前?只有文件1在前才能保证b的输出正确。

同样的改进:
文件1:

int &GetA()
      static int a =1;
      return a;

文件2:

int b = GetA() * 3;

则可以解决问题。所以跨编译单元的初始化问题,用local static对象替换non-local static对象。方法的重要思想是不要使变量有全局的作用域

参考:https://www.cnblogs.com/jerry19880126/archive/2013/03/09/2951186.html

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容