1、首先区分初始化和赋值。
初始化:创建对象时赋给初始值。赋值:擦除对象当前值,并用新值代替。因此,区分初始化和赋值的关键是,看看对象当前是否已经有值了。
2、创建对象的时候,如果没有初始化,对象的值是什么?
取决于对象的类型和对象定义的位置。
a、如果对象是内置类型,定义在方法外,它的值为0,定义在方法内,没有初始化。
b、如果对象是类类型,无论定义在哪里,都会调用默认构造方法,也就是说,对于类类型的对象,不存在没有初始化的情况。
3、现在考虑,类中的数据成员,也就是字段。类的构造方法执行两个过程:成员初始化列表和方法内赋值。对于类类型,前者用于初始化,即copy构造;后者用于赋值,即copy赋值。对于内置类型,前者和后者都可用于初始化,如果前者没有初始化,可在后者中初始化。
4、如果没有在成员初始化列表中显式初始化,出现什么情况?
a、如果是类类型,隐式初始化,调用默认构造方法;
b、如果是内置类型,不被初始化,它的取值,按照变量初始化规则进行。它的取值依赖于所属对象的作用域,所属对象是局部对象,不被初始化,所属对象是全局对象,初始化为0。如果内置类型是static字段呢?static字段必须在头文件之外定义(static+const+int是个特殊情况,可以只声明,不定义),定义时没有初始化,取值多少?因为它是类作用域内的全局变量,取值为0。
5、因此,对于类类型,,在方法内赋值,相当于执行了一次初始化,一次赋值。为了效率,应该在成员初始化列表中初始化。对于内置类型,两种方式等效,为了一致性,也在成员初始化列表中进行。但是,有三种情况必须在初始化列表中进行:a、类类型没有默认构造方法;b、引用;c、const对象。
6、类中字段的初始化顺序与初始化列表的顺序无关,而是与类定义中的声明顺序保持一致。
7、static对象可认为包括:全局对象,定义在namespace内的对象,在class内、方法内、以及file内的static对象。根据作用域可分为local static对象和non-local static对象,方法内的static对象时local static对象,其他的static对象是non-local static对象。
8、现在考虑,不同编译单元中non-local static对象的初始化顺序。C++中,对于不同编译单元的non-local static对象的初始化顺序没有明确定义,也就是说初始化顺序是不确定的。思考,为什么C++不定义,因为做不到。因为C++是单独分别编译,当前编译单元的编译不依赖其他编译单元的编译。
9、那怎么解决上面的问题呢?
使用一个方法,方法内部创建一个local static对象,返回这个local static 对象。对于多线程系统,为了保证只有一个local static对象,需要使用加锁机制。