Effective-cpp-4

Make sure that objects are initialized before they're used

尽量使用member initialization list

  • 如果只是在构造函数体内进行赋值,非内置类型会在default构造函数中先被初始化
1
2
3
4
5
6
7
8
9
10
class myClass{
public:
myClass(std::string& address, std::list<myClass>& l){
addr = address;//只是赋值,早在默认构造函数已经被初始化
list = l;
}
private:
std::string addr;
std::list<myClass> list;
};
  • 如果使用member initialization list,会更加高效,避免了内置类型进行结果相同的初始化和赋值;而且member initialization list也能通过默认构造函数初始化成员变量;
1
2
3
4
myClass::myClass()
:addr(),
list()
{}
  • C++的成员初始化次序是固定
    • base class-> derived class
    • class的成员变量按照声明次序初始化;

不同编译单元的non-local static对象

  • 这个问题的起源是C++不保证不同的编译单元的初始化次序。
  • 例如
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//file1.cpp
class FileSystem{
public:
std::size_t numDisks() const;
};
extern FileSystem tfs;

//file2.cpp
class Dir{
public:
Dir(params){
std::size_t disks = tfs.numDisks();
};
};
  • 在这种情况,倘若tfs在tempDir初始化并没有完成初始化,这样就会出现问题;

为了解决这个问题,我们采取singleton模式,把每个non-local static放到专属函数中。以local static对象替代non-local static对象。因为C++保证一个local static对象会在函数调用期间/首次遇到该对象被定义时进行初始化。

1
2
3
4
5
6
FileSystem& tfs()
{
static FileSystem fs;
return fs;
}//第一行是定义并初始化一个对象,第二行是返回该对象的引用。
//而且如果函数被反复调用,可以声明为inline

建议

  • 构造函数最好使用member initialization list;
  • 以local static对象替代non-local static对象,保证跨编译单元的对象初始化;