条款04:确定对象被使用前已被初始化
来源:互联网 发布:Date java 编辑:程序博客网 时间:2024/06/05 19:15
条款04:确定对象被使用前已被初始化
Make sure that object are initialized befor they’re used.
What
C++的语法规定:
1. C++不保证初始化内置型对象。
2. 对于内置类型以外的任何其他东西,初始化责任落在构造函数(constructors)身上。C++规定,对象的成员变量的初始化动作发生在进入构造函数本体之前。
3. C++有着十分固定的“成员初始化次序”。Base classes 更早于其derived classes 被初始化,而class的成员变量总是以其声明次序被初始化。详细:基类首先被初始化(如果存在的话,如果是多重继承,那先初始化虚继承,然后再依次初始化),然后就是依据声明的次序依次初始化,如果初始化列表中存在定义,则调用初始化列表中的方法进行初始化,如果没有在初始化列表中初始化,那对于基本类型就根据编译器而定,类对象则调用其默认构造函数进行初始化(如果存在的话,如果不存在就必须在初始化列表中初始化)。
4. 成员变量是 const 或 references,它们就一定需要初值,不能被赋值。
5. C++对于“定义跨编译单元内的non-local static对象”的初始化相对次序并无明确定义。
6. C++中的static对象是指存储区不属于stack和heap、"寿命"从被构造出来直至程序结束为止的对象。这些对象包括全局对象,定义于namespace作用域的对象,在class、function以及file作用域中被声明为static的对象。其中,函数内的static对象称为local static 对象,而其它static对象称为non-local static对象。
7. 对于local static对象,在其所属的函数被调用之前,该对象并不存在,即只有在第一次调用对应函数时,local static对象才被构造出来。而对于non-local static对象,在main()函数开始前就已经被构造出来,并在main()函数结束后被析构,例子祥见最后一页代码。
Why
Ø 读取未初始化的值会导致不明确的行为。在某些平台上,仅仅只是读取未初始化的值,就可能让你的程序停止与你运行。更可能的情况是读入一些“伴随机”bits,污染了正在进行读取动作的那个对象,最终导致不可测知的程序行为,以及许多令人不许快的调试过程。
Ø 由于进入构造函数本体之后并非初始化,因此构造函数体内的对成员变量的赋值,实际上是伪初始化(pseudo-initialization),伪初始化效率低下:如果没有提供初始化列表,那么进入构造函数体之前,各成员变量已经调用默认构造函数初始化(自定义类型)或由编译器决定(内置类型对象的初始化),函数体内再赋值。
Ø 初始化列表中:成员出现的次序即使不是声明的次序,也不会改变初始化默认的初始化顺序:按声明次序初始化class member。如果不按照声明次序写,会引起难以理解的错误(多个成员变量的初始化带有次序性)
例如:
初始化数组时需要指定大小,因此代表大小的那个变量必须先初始化。
Ø 由于what中的第五条引发了一个问题:如果某编译单元内的某个non-local static 对象的初始化动作使用了另一个编译单元内的某个non-local static对象,它所用到这个对象可能尚未被初始化,这就带来不明确的行为。所以必须解决相互依赖的类对象间的初始化。
How
1. 为避免需要记住变量何时需要初始化,何时不需要初始化,最简单的做法就是:总是初始化。
2. 为内置型对象进行手工初始化。
3. 构造函数最好使用成员初始化列表(member initialization list),而不要再构造函数本体内使用赋值(assignment).
4. 初始化列表中成员初始化顺序遵循声明的顺序,避免晦涩的错误。
5. 由于what中的第7点,我们将每一个non-local static对象放到自己的专属函数内(该对象在此函数内被声明为static),这些函数返回一个reference指向它所含的对象。将“函数调用”返回一个reference指向local static对象替换“直接访问non-local static对象”。你就保证了用到该对象时,它已被初始化,而且从未调用是,还不会引发构造函数成本(non-local static却不是这样高效)。这在模式设计中是Singleton(单例)模式的一种常见手法。
6. 上点中local static reference-returning函数往往结构就是这么简单(看下面图片例子):第一行定义并初始化一个local static对象,第二行就返回它。在被频繁调用的时候,inline的修饰是最佳的选择。
7. 在多线程模式下,任何一种non-const static对象,不论是local还是non-local,等待某事的发生都会有麻烦。处理这个麻烦的一种做法:在程序的单线程启动阶段(single-threaded startup portion)手工调用所有上一点的函数,这可消除与初始化有关的“竞速形式(race conditions)”。
#include <iostream>using namespace std;class LocalStaticClass {public: LocalStaticClass(){cout<<"Local static object constructed"<<endl;} ~LocalStaticClass(){cout<<"Local static object destructed"<<endl;} };class ClassInnerClass {public: ClassInnerClass(){cout<<"Class inner object constructed"<<endl;} ~ClassInnerClass(){cout<<"Class inner object destructed"<<endl;}};class FileStaticClass {public: FileStaticClass(){cout<<"File Static object constructed"<<endl;} ~FileStaticClass(){cout<<"File Static object destructed"<<endl;} };class WrapperClassA{ public: WrapperClassA(){} LocalStaticClass & singleton() { static LocalStaticClass LocalStaticObj; //local static object return LocalStaticObj; }};// class with non-local static objectclass WrapperClassB{public: WrapperClassB(){ } ~WrapperClassB(){ }//static data member declaration static ClassInnerClass ClassInnerObjB;//static声明 };ClassInnerClass WrapperClassB :: ClassInnerObjB;//ststic定义才会初始化 FileStaticClass file_static_class;int main( int argc,char * argv[]){ cout<<"main() started."<<endl; WrapperClassA objA;//objA.singleton(); //只有去掉注释执行该语句时,innerObjA才被构造出来 cout<<"main() terminated."<<endl; return 0;}
- [effictive c++] 条款04 确定对象被使用前已被初始化
- 条款04:确定对象被使用前已被初始化
- 条款4:确定对象被使用前已被初始化
- 条款04:确定对象被使用前已先被初始化
- 条款04:确定对象被使用前已先被初始化
- 条款04:确定对象被使用前已先被初始化
- Effective C++:条款04:确定对象被使用前已先被初始化
- [Effective C++]条款04 确定对象被使用前已先被初始化
- 条款04 确定对象被使用前已先被初始化
- 条款04:确定对象被使用前已先被初始化
- 条款04:确定对象被使用前已先被初始化
- 条款04:确定对象被试用前已被初始化
- Effective C++条款4:确定对象使用前已被初始化
- 条款4、确定对象在使用前已被初始化
- 条款4:确定对象被使用前已经被初始化
- 【Effective C++ 读书笔记】条款04:确定对象使用前已先被初始化
- 条款4:确定对象被使用前已先被初始化
- 条款4:确定对象被使用前已先被初始化
- Andriod Studio导入代码后中文乱码解决方案
- 二叉搜索树
- OC学习之道:OC中类别--Category类目的使用/Eetension类的扩展 的使用
- Python中如何遍历字典
- 程序的内存分配
- 条款04:确定对象被使用前已被初始化
- c++排序(快速排序)
- [leetcode]51 Two Sum
- COGS-313-和平委员会-POI2001-2-SAT
- 使用JPA进行数据操作
- java中Math.random()与java.util.random()的区别
- c++ template(9)trait和Policy
- Syntax error on token *,invalid variabledeclaratorid
- c++ template(8)模版多态