美文网首页Effective C++ 精读
Effective C++ Term 4 对象的初始化

Effective C++ Term 4 对象的初始化

作者: vancymoon | 来源:发表于2019-04-23 17:28 被阅读0次

利用成员初值列初始化成员变量

对于用户自定义类型来说,成员初值列的初始化效率比赋值操作要高,对于内置类型而言则差别不大
对于用户自定义类型,如果成员初值列没有为它们指定初值,编译器也会自动调用它们的默认构造函数,但为了避免不必要的遗漏,还是建议将成员初值列写完整:

Entry::Entry ( ) : Name(), Address, Phones(), times_consulted_(0) {
// ...
}

上例中,Name等都是用户自定义类型,成员初值列中制定了它们的默认构造函数进行初始化,times_consulted_是内置的int类型
C++对于成员初始化的次序总是由声明的顺序决定的,对于一个派生类,这一点也适用于基类与成员变量,如果成员变量早于构造函数被声明,那么成员变量的初始化要早于基类构造函数被调用;反之则是基类构造函数先被调用,可以自己做个小实验加以验证

non-local static 对象的初始化

在往下看之前,可以先阅读一下这篇文章
https://www.jianshu.com/p/92e81ecc8737

先说说什么是 static 对象,它的定义是:寿命从被构造出来直到程序结束为止。它包括:

  • global对象
  • 定义域 namespace 作用域内的对象(即对整个 namespace 都可见的 global-like 的变量)
  • 在 class 内、函数内、file 作用域内被显式声明为 static 的对象(加了 static 关键字)

在这五类 static 变量中,函数内的 static 对象称为 local static 对象,而其他四类统称为 non-local static 对象
程序结束时,即 main() 结束时,static 对象的析构函数会被自动调用
那么,non-local static 变量的初始化存在什么问题呢?那就是不同编译单元内定义的 non-local static 变量的初始化次序是不可预见的。其中,不同编译单元可以简单理解为两个源文件,而两个源文件中某个 non-local static 变量调用了另一个的 non-local static 变量,这就存在初始化问题了,因为这两个变量的初始化顺序对于程序员来说是不明确的,因此这种调用是有危险的,举个例子:有一个唯一的文件管理系统tfs定义如下

// FileSystem.h
Class FileSystem {
  ...
  std::size_t NumDisks() const;
  ...
};
extern FileSystem tfs;
// FileSystem.cc
FileSystem tfs;

客户调用tfs

std::size_t disks = tfs.numDisks();

这里的问题是diskstfs都是 non-local static 对象,而它们的初始化顺序是无法保证的,如果 disks 在初始化时tfs还未初始化,则会得到未定义的行为(我们也不知道真正取得的值是多少)
为了解决这个问题,我们可以借助 local static 的特性:函数内的 local static 对象会在该函数被调用期间首次遇上该对象之定义式时被初始化。简单来说, local static 对象初始化的等号=右边的对象会先初始化,然后再作为初始值传递给=左边,这样就不存在初始化顺序的问题了

// FileSystem.h
Class FileSystem {
  ...
  FileSystem& tfs() {
    static FileSystem fs;  // local-static 对象,保证了在该函数调用时,首次遇上fs时初始化
    return fs;
  }
  ...
};
// FileSystem.cc
FileSystem tfs;

客户调用tfs

std::size_t disks = tfs().numDisks();  // 先初始化 tfs 函数内的 fs,因此不存在前面所述问题

这也是单例(Singleton)模式所用到的手法

相关文章

网友评论

    本文标题:Effective C++ Term 4 对象的初始化

    本文链接:https://www.haomeiwen.com/subject/qpvvgqtx.html