1. 全局对象的内存会被初始化为0,但是Local对象由于在stack中,所以不会被清0,而是随机的垃圾数据。
2. Default constructor 的构建。如果没有用户定义的构造函数,则会有一个默认构造函数被implicitly构建出来,但这个构造函数是trivial constructor(没啥用处的)。如下四种情况下的类,编译器会构建nontrivial constructor出来(当然,如果该类有其他构造函数,却没有默认构造,则编译器会扩张每个构造函数而加入新的代码,却不生成新的构造函数):
a) 成员变量的类带有(不论是什么原因而带有的)默认构造函数。这时,编译器会扩张已经存在(或并不存在的)构造函数,插入代码来调用成员变量的构造函数。如果被调用的类(下同,基类等)没有默认构造函数,会报错。
b) 基类带有默认构造函数。这时,按照声明顺序依次调用基类的构造函数。
c) 新定义的或继承而得到虚函数。Vptr(每个对象)和vtbl(每个类)会给构造出来。
d) 有直接虚拟基类或继承链上有虚拟基类。
上述四种情况下,有implicit nontrivial constructor被构建,但他们只能符合编译器(而非程序)的要求。这四种情况之外,且没有声明任何constructor的类,可以说它有trivial constructor,但实际上它根本就不会被构建出来。
3. Copy constructor 的构建。三种情况可以以一个对象的内容来构建另一个对象的初值:X x2 = x1; foo(x2); return x2;
a) 如果没有提供显式的copy构造,则用default memberwise initialization手法完成,即:copy成员的值而非深层对象。
b) Bitwise copy(逐位copy)。对于基本类型和指针,会进行默认的shallow copy,而不进行调用构造函数这样的深度copy。这时,copy构造函数是trivial的,即编译器不会合成到程序中。
c) 类在下述四种情况下不具备Bitwise copy semantic,这时,nontrivial copy constructor会被构造出来:
Ø 成员变量的类带有(不论是何原因而有)拷贝构造函数。即:有“对象”成员,而非只有基本数据类型成员。
Ø 基类带有拷贝构造函数。
Ø 带有或继承而得到虚函数。重新设置vptr,并且,如果该对象是第一个对象的话还会构造vtbl。
Ø 有直接虚拟基类或继承链上有虚拟基类。
d) 指针成员的copy会带来name aliasing的问题:多个指针指向同一个内存。
4. 成员初始化队列(Member Initialization List,MIL)。
a) 必须使用MIL的场合:1)引用类型成员;2)const成员;3)基类构造函数有参数;4)成员变量构造函数有参数。
b) 用MIL进行初始化会避免产生先初始化对象再赋值的问题,因为成员在进入构造函数的 { 之前必须已被构造完成。
c) 其成员的构造函数执行顺序与“成员变量在class定义中的声明顺序” 严格一致,而无论MIL中的顺序如何;换句话说,MIL中的代码可能会被编译器调整顺序。并且,MIL的代码在任何的user code之前执行。
下面的代码是在学习过程中随便写的,错误和不严谨之处很多;甚至有一些地方只是做了一些记录和随笔。