one*_*tar 20 c++ initialization
给出以下代码:
class temp
{
public:
string str;
int num;
};
int main()
{
temp temp1;
temp temp2 = temp();
cout << temp1.str << endl; //Print ""
cout << temp2.str << endl; //Print ""
cout << temp1.num << endl; //Print a rand num
cout << temp2.num << endl; //Print 0
}
Run Code Online (Sandbox Code Playgroud)
这两者有什么不同? -
temp temp1;
Run Code Online (Sandbox Code Playgroud)
和
temp temp2 = temp();
Run Code Online (Sandbox Code Playgroud)
In *_*ico 23
temp temp1;
Run Code Online (Sandbox Code Playgroud)
这会temp在名为的实例上调用默认构造函数temp1.
temp temp2 = temp();
Run Code Online (Sandbox Code Playgroud)
这会temp在临时对象上调用默认构造函数,然后temp2使用临时对象作为参数调用编译器生成的复制构造函数(当然这假定编译器不会删除副本;它取决于编译器的优化设置) .
至于为什么你得到不同的初始值,标准的第8.5节是相关的:
T是指:
T是标量类型(3.9),则将对象设置为值0(零)转换为T;T是非联合类类型,则每个非静态数据成员和每个基类子对象都是零初始化的;T是联合类型,则对象的第一个命名数据成员为零初始化;T是数组类型,每个元素都是零初始化的;T是引用类型,则不执行初始化.到默认初始化的类型的对象T是指:
T是非POD类类型(第9节),T则调用默认构造函数(如果T没有可访问的默认构造函数,则初始化是错误的);T是数组类型,则每个元素都是默认初始化的;对值初始化类型的对象T意味着:
T是具有用户声明的构造函数(12.1)的类类型(第9节),然后T调用默认构造函数(如果T没有可访问的默认构造函数,则初始化是错误的);T是没有用户声明的构造函数的非联合类类型,则T的每个非静态数据成员和基类组件都是值初始化的;T是数组类型,则每个元素都是值初始化的;现在已经制定了规则,让我们看看它们是如何应用的:
temp temp1;
Run Code Online (Sandbox Code Playgroud)
temp是非POD类型(因为它有一个std::string成员),并且由于没有指定初始化程序temp1,它将被默认初始化(8.5/9).这会调用默认构造函数(8.5/5).temp有一个隐式默认构造函数(12/7),它默认初始化std::string成员,而int成员根本没有初始化(12.6.2/4).
temp temp2 = temp();
Run Code Online (Sandbox Code Playgroud)
另一方面,临时temp对象是值初始化的(8.5/7),它对所有数据成员(8.5/5)进行值初始化,调用std::string成员中的默认构造函数并对成员进行零初始化int(8.5/5) .
当然,如果您不必在5个以上的不同位置引用标准,只需确保明确初始化所有内容(例如int i = 0;或使用初始化列表).
代码的行为主要取决于您使用的编译器.更准确地说,它取决于编译器实现的语言规范版本.
对于C++ 98编译器,两个声明对声明的对象的最终值具有相同的效果:str成员应该变为空,而num成员应该包含不可预测的值.在这两种情况下,实际初始化都是由编译器提供的类的默认构造函数执行的默认初始化temp.该默认构造函数初始化str,但未num初始化.
对于C++ 03编译器,行为是不同的.temp1对象没有区别(它num仍然是不可预测的).但temp2初始化的处理方式不同.在C++ 03中,()初始化器触发了新的初始化 - 所谓的值初始化.值初始化忽略编译器提供的顶级对象的默认构造函数,而是直接在其子对象(本例中为数据成员)上工作.因此,temp2对象通过值初始化有效地初始化,这也将num成员设置为零(除了str用空字符串初始化).因此,temp2.num在C++ 03编译器中最终为零.
如果在您的实验中您观察到一致的零temp2.num,则意味着您的编译器在这方面遵循C++ 03规范.