利用成员初值列初始化成员变量
对于用户自定义类型来说,成员初值列的初始化效率比赋值操作要高,对于内置类型而言则差别不大
对于用户自定义类型,如果成员初值列没有为它们指定初值,编译器也会自动调用它们的默认构造函数,但为了避免不必要的遗漏,还是建议将成员初值列写完整:
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();
这里的问题是disks
和tfs
都是 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)模式所用到的手法
网友评论