本文主要给大家介绍了关于c++初始化方式的相关内容,分享出来供大家参考学习、下面话不多说了,来一起看看详细的介绍吧。
<强> c++小实验测试:强>下面程序中主要函数里一位和反方向的输出值是多少吗?
# include & lt; iostream> struct foo { foo()=违约; int; }; struct酒吧 { 酒吧(); int b; }; 酒吧:bar()=违约; int main () { foo {}; 酒吧b {}; std:: cout & lt; & lt;一个。& lt; & lt;‘\ t & lt; & lt;反方向; }
答案是一位是0,反方向是不确定值(不论你是gcc编译器,还是叮当声编译器,或者是微软的msvc + +编译器)。为什么会这样?这是因为c++中的初始化已经开始畸形发展了。
接下来,我要探索一下为什么会这样。在我们知道原因之前,先给出一些初始化的概念:默认初始化,值初始化,零初始化。
T全球;//T是我们的自定义类型,首先零初始化,然后默认初始化 空白foo () { T我;//默认初始化 T j {};//值初始化(C + + 11) T k=T ();//值初始化 T l={};//值初始化(C + + 11) T m ();//函数声明 新的T;//默认初始化 新的T ();//值初始化 新的T {};//值初始化(C + + 11) } 结构体的 { T T; ():t ()//t将值初始化 {//构造函数 } }; struct B { T T; B (): {}//t将值初始化(C + + 11) {//构造函数 } }; 结构C { T T; C ()//t将默认初始化 {//构造函数 }};
-
<李>默认初始化:如果T是一个类,那么调用默认构造函数进行初始化;如果是一个数组,每个元素默认初始化,否则不进行初始化,其值未定义。至于合成的默认构造函数初始化数据成员的规则是:1。如果类数据成员存在类内初始值,则用该值初始化相应成员(c + + 11); 2。否则,默认初始化数据成员。李>
<李>值初始化:如果T是一个类,那么类的对象进行默认初始化(如果T类型的默认构造函数不是用户自定义的,默认初始化之前先进行零初始化);如果是一个数组,每个元素值初始化,否则进行零初始化。李>
<李>零初始化:对于静态或者thread_local变量将会在其他类型的初始化之前先初始化。如果T是算数,指针,枚举类型,将会初始化为0;如果是类类型,基类和数据成员会零初始化;如果是数组,数组元素也零初始化。李>
看一下上面的例子,如果T是int类型,那么全球和那些T类型的使用值初始化形式的变量都会初始化为0(因为int是内置类型,不是类类型,也不是数组,将会零初始化,又因为int是算术类型,如果进行零初始化,则初始值为0)而其他的默认初始化都是未定义值。
回到开头的例子,现在我们已经有了搞明白这个例子所必要的基础知识。造成结果不同的根本原因是:foo和bar被它们不同位置的默认构造函数所影响。
foo的构造函数在起初声明时是要求默认合成,而不是我们自定义提供的,因此它属于编译器合成的默认构造函数,而酒吧的构造函数则不同,它是在定义时被要求合成,因此它属于我们用户自定义的默认构造函数。
前面提到的关于值初始化的规则时,有说明到:如果T类型的默认构造函数不是用户自定义的,默认初始化之前先进行零初始化。因为foo的默认构造函数不是我们自定义的,是编译器合成的,所以在对foo类型的对象进行值初始化时,会先进行一次零初始化,然后再调用默认构造函数,这导致一位的值被初始化为0,而酒吧的默认构造函数是用户自定义的,所以不会进行零初始化,而是直接调用默认构造函数,从而导致反方向的值是未初始化的,因此每次都是随机值。
如果你不想要你的默认构造函数是用户自定义的,那么必须在类的内部声明处使用“=违约”,而不是在类外部定义处使用。
对于类类型来说,用户提供自定义的默认构造函数有一些额外的“副作用”。比如,对于缺少用户提供的自定义默认构造函数的类,是无法定义该类的常量对象的。示例如下:
类执行 { int我; }; const exec e;//错误!缺少用户自定义默认构造函数,不允许定义const类对象以前c++中各种初始化方式示例详解