temp temp1;
这将在名为temp1
的实例上调用temp
的默认构造函数。
temp temp2 = temp();
这将在临时对象上调用
temp
的默认构造函数,然后使用临时对象作为参数调用
temp2
上的编译器生成的拷贝构造函数(当然,这假设编译器不会省略拷贝; 其取决于您的编译器优化设置)。
至于为什么会得到不同的初始化值,标准的第8.5节是相关的:
8.5 初始化[dcl.init]
段落5: 对类型为
T
的对象进行
零初始化 的意思是:
- 如果
T
是标量类型(3.9),则将对象设置为转换为T
的值为0(零);
- 如果
T
是非联合类类型,则对每个非静态数据成员和每个基类子对象进行零初始化;
- 如果
T
是联合类型,则对对象的第一个命名数据成员进行零初始化;
- 如果
T
是数组类型,则对每个元素进行零初始化;
- 如果
T
是引用类型,则不执行初始化。
对类型为
T
的对象进行
默认初始化的意思是:
- 如果
T
是非POD类类型(第9条),则调用T
的默认构造函数(如果T
没有可访问的默认构造函数,则初始化是非法的);
- 如果
T
是数组类型,则对每个元素进行默认初始化;
- 否则,对象将被零初始化。
对类型为
T
的对象进行
值初始化的意思是:
- 如果
T
是带有用户声明的构造函数(12.1)的类类型(clause 9),那么将调用T
的默认构造函数(如果T
没有可访问的默认构造函数,则初始化是非法的);
- 如果
T
是一个非联合类类型且没有用户声明的构造函数,则初始化T的每个非静态数据成员和基类组件的值;
- 如果
T
是数组类型,则对每个元素进行值初始化;
- 否则,对象将被零初始化。
段落7: 初始化程序为空括号集的对象,即(),应进行值初始化。
第9段:
如果一个对象没有指定初始化器,并且该对象是(可能带有cv限定符的)非POD类类型(或其数组),则该对象应进行默认初始化;如果该对象是const限定类型,则底层类类型必须具有用户声明的默认构造函数。否则,如果未为非静态对象指定初始化器,则该对象及其子对象(如果有)具有不确定的初始值;如果该对象或其任何子对象是const限定类型,则程序是非法的。
12特殊成员函数[special]
第7段:
对于一个类,当它被用于创建其类类型的对象时(1.8),隐式声明的默认构造函数会被隐式定义。隐式定义的默认构造函数执行与该类的空mem-initializer-list(12.6.2)和空函数体的用户编写的默认构造函数将执行的类的初始化集相同。
12.6.2初始化基类和成员[class.base.init]
第4段:
如果给定的非静态数据成员或基类没有被mem-initializer-id命名(包括构造函数没有ctor-initializer的情况),则
- 如果实体是(可能带有cv限定符的)类类型(或其数组)或基类的非静态数据成员,并且实体类是非POD类,则该实体将被默认初始化(8.5)。如果实体是const限定类型的非静态数据成员,则该实体类必须具有用户声明的默认构造函数。
- 否则,该实体未被初始化。如果实体是const限定类型或引用类型,或者是包含(直接或间接地)const限定类型成员的(可能带有cv限定符的)POD类类型(或其数组),则程序是非法的。
现在规则已经说明,让我们看看它们如何应用:
temp temp1;
temp
是一个非POD类型(因为它有一个
std::string
成员),由于
temp1
没有指定初始化值,因此将进行默认初始化(8.5/9)。这将调用默认构造函数(8.5/5)。
temp
具有隐式的默认构造函数(12/7),该函数会对
std::string
成员进行默认初始化,而
int
成员则不会被初始化(12.6.2/4)。请注意保留HTML标签。
temp temp2 = temp();
另一方面,临时的
temp
对象会进行值初始化 (8.5/7),这会对所有数据成员进行值初始化 (8.5/5),也就是会调用
std::string
成员的默认构造函数,并将
int
成员进行零初始化 (8.5/5)。
当然,如果你不想在五个或更多地方引用标准文档的话,可以确保显式初始化每一个变量 (例如,使用
int i = 0;
或者使用初始化列表)。