C++中各种初始化方式示例详解分享

—-想了解C++中各种初始化方式示例详解分享的全部内容且更多的C语言教程关注<计算机技术网(www.ctvol.com)!!>

前言

C++中各种初始化方式示例详解分享主要给大家介绍了关于C++初始化方式的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。

C++小实验测试:下面程序中main函数里a.a和b.b的输出值是多少?

  #include <iostream>    struct foo  {   foo() = default;   int a;  };    struct bar  {   bar();   int b;  };    bar::bar() = default;    int main()  {   foo a{};   bar b{};     std::cout << a.a << 't' << b.b;  }

答案是a.a是0,b.b是不确定值(不论你是gcc编译器,还是clang编译器,或者是微软的msvc++编译器)。为什么会这样?这是因为C++中的初始化已经开始畸形发展了。

接下来,我要探索一下为什么会这样。在我们知道原因之前,先给出一些初始化的概念:默认初始化,值初始化,零初始化。

  T global;    //T是我们的自定义类型,首先零初始化,然后默认初始化    void foo()  {   T i;  //默认初始化   T j{}; //值初始化(C++11)   T k = T(); //值初始化   T l = T{}; //值初始化(C++11)   T m(); //函数声明     new T; //默认初始化   new T(); //值初始化   new T{}; //值初始化(C++11)  }    struct A  {   T t;   A() : t() //t将值初始化   {   //构造函数   }  };    struct B  {   T t;   B() : t{} //t将值初始化(C++11)   {   //构造函数   }  };    struct C  {   T t;   C()  //t将默认初始化   {   //构造函数   }  };

上面这些不同形式的初始化方式有点复杂,我会对这些C++11的初始化做一下简化:

看一下上面的例子,如果T是int类型,那么global和那些T类型的使用值初始化形式的变量都会初始化为0(因为int是内置类型,不是类类型,也不是数组,将会零初始化,又因为int是算术类型,如果进行零初始化,则初始值为0)而其他的默认初始化都是未定义值。

回到开头的例子,现在我们已经有了搞明白这个例子所必要的基础知识。造成结果不同的根本原因是:foo和bar被它们不同位置的默认构造函数所影响。

foo的构造函数在起初声明时是要求默认合成,而不是我们自定义提供的,因此它属于编译器 合成的 默认构造函数 。而bar的构造函数则不同,它是在定义时被要求合成,因此它属于我们用户 自定义的 默认构造函数 。

前面提到的关于值初始化的规则时,有说明到: 如果T类型的默认构造函数不是用户自定义的,默认初始化之前先进行零初始化 。因为foo的默认构造函数不是我们自定义的,是编译器合成的,所以在对foo类型的对象进行值初始化时,会先进行一次零初始化,然后再调用默认构造函数,这导致a.a的值被初始化为0,而bar的默认构造函数是用户自定义的,所以不会进行零初始化,而是直接调用默认构造函数,从而导致b.b的值是未初始化的,因此每次都是随机值。

这个陷阱迫使我们注意:如果你不想要你的默认构造函数是用户自定义的,那么必须在类的内部声明处使用”=default”,而不是在类外部定义处使用。

对于类类型来说,用户提供自定义的默认构造函数有一些额外的“副作用”。比如,对于缺少用户提供的自定义默认构造函数的类,是无法定义该类的const对象的。示例如下:

  class exec  {   int i;  };    const exec e;  //错误!缺少用户自定义默认构造函数,不允许定义const类对象

通过开头的例子,我们已经对C++的一些初始化方式有了直观的感受。 C++中的初始化分为6种:零 初始化、 默认初始化、值初始化、直接初始化、拷贝初始化、列表初始化。

零初始化和变量的类型和位置有关系,比如是否static,是否aggregate聚合类型。能进行0初始化的类型的对象的值都是0,比如int为0,double为0.0,指针为nullptr;

现在我们已经了解了几种初始化的规则,下面则是几种初始化方式的使用形式:

1. 默认初始化是定义对象时,没有使用初始化器,也即没有做任何初始化说明时的行为。典型的:

  int i;  vector<int> v;

2. 值初始化是定义对象时,要求初始化,但没有给出初始值的行为。典型的:

  int i{};  new int();  new int{}; //C++11

3. 直接初始化和拷贝初始化主要是相对于我们自定义的对象的初始化而言的,对于内置类型,这两者没有区别。对于自定义对象,直接初始化和拷贝初始化区别是直接调用构造函数还是用”=”来进行初始化。典型的:

  vector<int>  v1(10); //直接初始化,匹配某一构造函数  vector<string> v2(10); //直接初始化,匹配某一构造函数  vector<int>  v3=v1;  //拷贝初始化,使用=进行初始化

对于书本中给出的示例:

  string dots(10, '.'); //直接初始化  string s(dots);      //直接初始化

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/c-cdevelopment/488601.html

(0)
上一篇 2020年11月12日
下一篇 2020年11月12日

精彩推荐