给定以下代码:
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
}这两者有什么不同?
temp temp1;和
temp temp2 = temp();发布于 2011-05-14 11:01:57
temp temp1;这将在名为temp1的实例上调用temp的默认构造函数。
temp temp2 = temp();这会在临时对象上调用temp的默认构造函数,然后在temp2上调用编译器生成的复制构造函数,并将临时对象作为参数(当然,这假设编译器不会省略副本;这取决于编译器的优化设置)。
至于为什么会得到不同的初始化值,标准的8.5节是相关的:
8.5初始化器dcl.init
第5段:
对T类型的对象进行零初始化意味着:
如果T;
T是数组类型,T T是一个数组类型,每个元素都是零初始化的;
T是引用类型,则不执行初始化。默认初始化T类型的对象意味着:
T是非POD类类型(第9条),则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化是错误的) T是数组类型,每个元素都是对象对象是zero-initialized.对值初始化T类型的对象意味着:
T是具有用户声明的构造函数(12.1)的类类型(第9条),则调用T的默认构造函数(并且初始化是病态的如果T没有可访问的默认构造函数T是没有用户声明的构造函数的非联合类类型,则T的每个非静态数据成员和基类组件都是非静态数据成员和基类组件T是数组类型,则每个元素都是值初始化的;否则,该对象为zero-initialized.
第7段:
初始化器是一组空括号的对象,即(),应该是值初始化的。
第9段:
如果没有为对象指定初始值设定项,并且对象是(可能是cv限定的)非POD类类型(或其数组),则应默认初始化对象;如果对象是常量限定类型,则底层类类型应具有用户声明的默认构造函数。否则,如果没有为非静态对象指定初始值设定项,则该对象及其子对象(如果有的话)具有不确定的初始值;如果该对象或其任何子对象是const限定类型,则程序的格式不正确。
12特殊成员函数特殊
第7段:
隐式声明的类的默认构造函数在用于创建其类类型的对象时被隐式定义(1.8)。隐式定义的默认构造函数执行类的一组初始化,这些初始化将由用户为该类编写的默认构造函数执行,其中具有空的mem-initializer-list (12.6.2)和空的函数体。
12.6.2初始化基和成员class.base.init
第4段:
如果给定的非静态数据成员或基类不是由mem-initializer-id命名的(包括由于构造函数没有ctor-initializer而没有mem-initializer-list的情况),则
现在规则已经制定好了,让我们看看它们是如何应用的:
temp temp1;temp是一个非POD类型(因为它有一个std::string成员),并且由于没有为temp1指定初始化器,它将被默认初始化(8.5/9)。这将调用默认构造函数(8.5/5)。temp有一个隐式的默认构造函数(12/7),它默认初始化std::string成员,而int成员根本不初始化(12.6.2/4)。
temp temp2 = temp();另一方面,临时temp对象是值初始化的(8.5/7),它对所有数据成员进行值初始化(8.5/5),它调用std::string成员中的默认构造函数并对int成员进行零初始化(8.5/5)。
当然,如果你不想引用5+中不同地方的标准,只需要确保你显式地初始化了所有东西(例如int i = 0;或使用初始化器列表)。
发布于 2011-05-14 11:30:49
代码的行为很大程度上取决于您所使用的编译器。更准确地说,这取决于编译器实现的语言规范的版本。
对于C++98编译器,这两个声明对所声明的对象的最终值具有相同的影响:str成员应为空,而num成员应包含不可预知的值。在这两种情况下,实际的初始化都是由编译器提供的类temp的默认构造函数执行的默认初始化。该默认构造函数初始化str,但未初始化num。
对于C++03编译器来说,这种行为是不同的。temp1对象没有区别(它的num仍然是不可预测的)。但是temp2初始化的处理方式不同。在C++03中,()初始化器触发一种新的初始化--即所谓的值初始化。值初始化忽略编译器提供的顶级对象的默认构造函数,而是直接作用于其子对象(本例中为数据成员)。因此,通过值初始化可以有效地初始化temp2对象,这也会将num成员设置为零(除了使用空字符串初始化str之外)。因此,在C++03编译器中,temp2.num最终为零。
如果您在实验中观察到temp2.num中一致的零,这意味着您的编译器在这方面遵循C++03规范。
发布于 2011-05-14 11:05:23
temp temp1;将创建一个默认的初始化temp对象。由于您没有为temp提供默认构造函数,因此temp的每个成员也将被默认初始化。因为std::string提供了一个默认的ctor,所以它被正确地初始化,并且有一个定义良好的值。但是,整数会默认初始化,这是由实现定义的,通常是一个随机值。
temp temp2 = temp();这将首先创建一个值初始化的temp对象。这一点很重要,因为对象本身是值初始化的,它的成员也是如此。这对于字符串来说并不重要,因为默认值和值初始化是相同的,但是对于整数来说却很重要。值初始化后的整数的值为0。
在此之后,只需将这些成员复制到temp2中。
此外,您可能会对this relevant question感兴趣。
编辑:请参阅我在@In silico的回答中的评论,以了解为什么MSVC不是这样的。:/
https://stackoverflow.com/questions/5999522
复制相似问题