在C++中,关于对象的初始化动做什么时候必定发生,什么时候不必定发生这个问题,最佳的处理办法就是:永远在使用对象以前先将它初始化。安全
关于在构造函数中初始化,重要的一点是不要混淆了赋值和初始化。函数
class PhoneNumber { ... }; class ABEntry { private: std::string theName; std::string theAddress; std::list<PhoneNumber> thePhones; int numTimesConsulted; public: ABEntry{const std::string &name, const std::string &address, const std::list<PhoneNumber> &phones}; }; /* 正确可行但不是最好的方法:在构造函数体内对成员变量进行赋值 */ ABEntry::ABEntry{const std::string &name, const std::string &address, const std::list<PhoneNumber> &phones} { theName = name; //theName、theAddress、thePhones都是赋值, theAddress = address; //而不是初始化。 thePhones = phones; numTimesConsulted = 0; } /* 较好的方法:使用初始化列表对成员变量进行初始化 */ ABEntry::ABEntry{const std::string &name, const std::string &address, const std::list<PhoneNumber> &phones} :theName(name), theAddress(address), thePhones(phones), numTimesConsulted(0) //为了一致性,内置类型对象初始化最好也在初始化列表中进行 { }
对大多数类型而言,比起先调用default构造函数而后再调用operator =,单只调用一次copy构造函数是比较高效的,有时甚至高效得多。
而对于内置类型对象如numTimesConsulted,其初始化和赋值的成本是同样的,但为了一致性最好也经过初始化列表来初始化。线程
若是成员变量是const或reference,那么不论是内置类型仍是自定义类型,都必定须要初值,不能被赋值,都只能经过初始化列表进行初始化(见条款5)。
为避免须要记住什么时候必须使用初始化列表,什么时候不须要,最简单的作法就是:设计
可是,一些class有多个构造函数,并且有许多成员变量和/或base class,若是每一个构造函数都使用初始化列表,那么就会形成大量的代码重复。
这种状况下,能够合理地对"赋值和初始化开销同样"的成员变量改用赋值操做,并将这些赋值操做封装到一个private init函数中,供全部构造函数调用。
这种作法在"成员变量的初始值来自于文件或数据库读入"时特别有用。然而,比起经由赋值操做完成的"伪初始化",经过初始化列表完成的"真正初始化"一般更加可取。code
C++在单个对象建立时有着十分固定的成员初始化顺序,口诀就是"先父母,再客人,后本身"。对象
若是已经在初始化列表中对base class和全部成员变量进行了初始化,那就只剩下一个问题——"不一样源文件内定义的non-local static对象"的初始化问题。
先来明确下概念,函数内定义的static对象称为local static对象,其余地方定义的static对象称为non-local static对象。
如今,咱们关心的问题涉及至少两个源文件,每一个源文件中都至少含有一个non-local static对象,所以可能发生以下问题。string
产生该问题的缘由是C++对不一样源文件中的non-local static对象初始化顺序没有明肯定义,幸运的是经过一个小小的设计即可彻底消除该问题,惟一须要作的是:it
该方法其实是用local static对象替换了non-local static对象,这也是Singleton模式的一个常见实现手法。该方法之因此管用,是由于:编译
能够看到,这种结构下的函数体每每十分简单固定:第一行定义并初始化一个local static对象,第二行返回一个引用指向它。
这使得它们很是适合实现为inline函数,尤为是须要被频繁调用的场合;但从另外一个角度看,内含static对象也使得它们成为线程不安全函数。
class FileSystem { ... }; //static FileSystem tfs; //FileSystem.cpp中定义的non-local static对象 //tfs的专属函数,用来替换tfs对象 FileSystem &tfs() { static FileSystem fs; //定义并初始化一个local static对象fs return fs; //返回一个reference指向上述对象 }
class Directory { ... }; Directory::Directory() { //... std::size_t disks = tfs().numDisks(); //... } //static Directory tempDir; //Directory.cpp中定义的non-local static对象,tempDir的初始化依赖于FileSystem.cpp中的tfs对象先初始化完成 //tempDir的专属函数,用来替换tempDir对象 Directory &tempDir() { static Directory td; //定义并初始化一个local static对象td return td; //返回一个reference指向上述对象 }