effect C++ 确定对象被使用前先被初始化
2017-03-22 16:24
302 查看
将对象初始化
int x 在某些语境下x保证初始化(为0),但在其他语境中却不保证。class Point{ int x , int y; } .... Point p ;
p的成员变量有时候初始化(为0),有时不会。读取未初始化的值会导致不明确行为。
最佳的处理办法就是:永远在使用对象之前将他们初始化。对于无任何成员的内置类型,必须手工完成此事。
int x =0; const char * text ="A-C-style string"; double d ; std::cin>>d; //以读取input stream的方式完成初始化
确保每一个构造函数都将对象的每一个成员初始化。
注意别混淆了赋值和初始化。class PhoneNumber {...} class ABEntry{ public: ABEntry(const std::string& name,const std::string&address,const std::list<PhoneNumber>&phones); private: std:: string theName; std:: string theAddress; std:: list<PhoneNumber>thePhones; int numTimesConsulted; }; ABEntry::ABEntry(const std::string&name,const std::string &address,const std::list<PhoneNumber>&phones) { theName=name; //这些都是赋值 theAddress=address; //而非初始化 thePhones=phones; numTimesConsulted=0; }
C++规定,对象的成员变量的初始化动作发生在进入构造函数本体之前
较佳的一个写法是:
ABEntry::ABEntry(const std:: string &name,const std::string&address, const std::list<PhoneNumber>&phone):theName(name),theAddress(address),thePhones(phones),numTimesConsulted(0) //这些都是初始化 {}
通常效率更高,基于赋值的那个版本首先调用default构造函数为成员赋初值,然后立刻重新赋值。
总使用成员初值列。
不同编译单元内定义之non-local static 对象
static对象 ,其寿命从构造出来直到程序结束为止(stack和heap-based对象都被排除)。这种对象包括global对象,定义于namesapce作用域的对象、在classes内、函数内、以及在file作用域内被声明为static的对象。 函数内的static对象被称为local static对象(因为它们对函数而言是local),其他的对象称为non-local对象。程序结束时static对象会被自动销毁,它们的析构函数会在main()结束时调用。编译单元是产出单一目标文件的那些源码,基本是单一源码加上其所含入的头文件。
现在至少有两个源码文件,每一个内含至少一个non-local static 对象(也就是该对象是global或位于namespace作用域内,抑或在class内或file作用域内被声明为static)。真正的问题是:如果某编译单元内某个non-local static对象的初始化动作使用了另一编译单元内的某个non-local static对象,它所用到的这个对象可能未被初始化。
例:
class FileSystem{ public: ... std::size_t numDisks()const; //众多成员函数之一 ... } extern FileSystem tfs; //预备给客户使用的对象假设用户建立一个class
class Directory{ public: Directory(params); ... }; Directory::Directory(params) { ... std::size_t disks=tfs.numDisks(); //使用tfs对象 ... }如果客户决定创建一个Director对象
Director tempDir (params);除非tfs在tempDir之前被初始化,否则tempDir的构造函数会用到尚未初始化的tfs。它们是定义在不同编译单元内的non-local static 对象。
解决:
将每个non-local static 对象搬到自己的专属函数内(该对象在此函数内被声明为static)。这些函数返回一个reference 指向它所含的对象。然后用户调用着这些函数,而不是指涉这些对象。 non-local static 对象被 local static 对象替换了。(Singleton模式的一个常见的实现手法)
C++保证,函数内的local static 对象会在“该函数被调用期间”“首次遇上该对象之定义式”时被初始化。所以如果以“函数调用”(返回一个reference指向local static对象)替换“直接访问non-local static对象”,就可以保证获得的那个reference将指向一个历经初始化的对象。如果从未调用 non-local static 对象的“仿真函数”,就绝不会引发构造和析构成本。
class FileSystem{...} //同前 FileSystem& tfs() //这个函数用来替换tfs对象;它在FileSystem class 中可能是个static { static FileSystem fs; //定义并初始化一个local static对象 return fs; //返回一个reference指向上述对象 } class Directory{...}; //同前 Directory::Directory(params) { ... std::size_t disks =tfs().numDisks();//原本的reference to tfs现在改为tfs() } Directory&tempDir() //这个函数用来替换tempDir对象,它在Directory中可能是一个static { static Directory td; //定义并初始化local static 对象 return td; //返回一个reference指向上述对象 }
这样,客户使用tfs()和tempDir()而不再是tfs和tempDir,使用的是指向static对象的reference
为内置型对象进行手工初始化,因为C++不保证初始化它们。
构造函数最后使用成员初值列,而不要在构造函数本体内使用赋值操作。初值列列初的成员列表,其排列次序应该和它们在class中声明的次序相同。
为免除“跨编译单元之初始化次序”问题,请以local static 对象替换non-local static 对象。
相关文章推荐
- 《Effect C++》学习------条款04:确定对象被使用前以先被初始化
- 条款04:确定对象被使用前已先被初始化
- [Effective C++读书笔记]004_条款04_确定对象被使用前已先被初始化
- 确定对象被使用前巳先被初始化
- Effective C++(4) 确定对象被使用前已先被初始化
- EffictiveC++之确定对象在使用前被初始化
- 条款四 确定对象被使用前已先被初始化
- effective c++条款04确定对象使用前已经被初始化
- 确定对象在被使用前被初始化(Make sure that objects are initialized before they’re used)——effective c++学习笔记
- Effective C++ 条款4——确定对象被使用前已先被初始化
- Effective C++笔记之三确定对象在使用前已初始化
- 确定一个对象在使用前已经被初始化
- [Effective C++]条款04:确定对象被使用前已先被初始化
- 条款04:确定对象被使用前已先被初始化
- 确定对象在被使用前被初始化(Make sure that objects are initialized before they’re used)——effective c++学习笔记
- 条款4:确定对象被使用前已先被初始化
- 条款4:确定对象使用前已先被初始化
- Effective C++学记之04 确定对象被使用前先被初始化
- 条款04:确定对象被使用前已先被初始化
- Effective c++ 学习笔记——条款04:确定对象被使用前已先被初始化