目录

  • 什么是初始化
  • 初始化方式
    • 默认初始化
    • 值初始化
    • 直接初始化/拷贝初始化
    • 列表初始化
  • 默认初始值
  • 参考

什么是初始化

当对象在创建时获得了一个特定的值,我们就说这个对象被初始化了。

注意:在C++语言中,初始化和赋值是两个完全不同的操作。
初始化创建变量时赋予其一个初始值。
赋值:把对象的当前值删除,并赋予一个新的值。
而在很多类中,初始化和赋值的区别事关底层效率问题:前者直接初始化数据成员,后者则先初始化再赋值。

初始化方式

默认初始化

在下面情况发生:

  • 在块作用域中定义非静态变量或者数组时没有赋初值
{int var;int arr[10];
}
  • 当一个类本身含有类类型的成员且使用合成的默认构造函数时
class B {int a = 1;int b = 2;
};
class A {B m_b;
};
  • 当类类型的成员没有在构造函数初始化列表中显示地初始化时

简单来说,如果在变量初始化时没有指定初始值,则变量进行默认初始化,此时变量被赋予了默认值,默认值到底是什么由变量类型变量的位置决定的,我们后面会具体讲解

值初始化

值初始化是只使用了初始化器(即使用了圆括号或花括号)但却没有提供初始值的情况

int main()
{int *p = new int();//值初始化vector<int> vec(10);//值初始化//int a();错误的初始化方式int a = int();//值初始化return 0;
}

注意:当不采用动态分配内存的方式(即不采用new运算符)时,写成int a();是错误的值初始化方式,因为这种方式声明了一个函数而不是进行值初始化。如果一定要进行值初始化,必须结合拷贝初始化使用,即写成int a=int();

  • 对于内置类型初始值为0
  • 对于类类型则调用其默认构造函数,如果没有默认构造函数,则不能进行值初始化。
class A {//由于显示声明了构造函数,所以没有默认构造函数
public:A(int x) {a = x;}int a;
};int main()
{A object{};//由于没有默认构造函数,初始化出错cout << object.a << endl;return 0;
}

直接初始化/拷贝初始化

直接初始化与拷贝初始化对应,其内部实现机理不同。

  • 直接初始化在下面情况下发生

    • 采用圆括号的方式进行变量初始化

    与值初始化不同,括号里一定要有初始值

    • 用emplace成员创建的元素都进行直接初始化
  • 拷贝初始化在下面情况下发生
    • 采用等号(=)进行初始化
    • 从一个返回类型为非引用类型的函数返回一个对象
    • 用列表初始化一个数组中的元素
int main()
{int a(5);//直接初始化vector<int>vec1(10);//值初始化vector<int>vec2(vec1);//直接初始化vector<int>vec3(10,1);//直接初始化int b = 10;//拷贝初始化;vector<int>vec4 = vec3;//拷贝初始化
}

当使用直接初始化时,我们实际上是要求编译器使用普通的函数匹配来选择与我们提供的参数最匹配的构造函数。

注意:虽然拷贝初始化看起来像是给变量赋值,实际上是执行了初始化操作,与先定义再赋值本质不同。可以看下面例子;

在这里插入代码片class Foo
{public:Foo() {cout << "Foo()" << endl;};Foo(int n) {cout << "Foo(int n)" << endl;}Foo(const Foo&x) {cout << "Foo(const Foo&x)" << endl;}Foo& operator=(const Foo&x) {cout << "Foo& operator=(const Foo&x) " << endl;return *this;}Foo& operator+(const Foo&x) {a += x.a;cout << "Foo& operator+(const Foo&x) " << endl;return *this;}int a=1;
};
int main()
{Foo f1;//默认初始化Foo f2 = f1;//拷贝初始化Foo f3=f1+f2;//拷贝初始化f3 = f2;//赋值操作
}

输出结构:

可以看到在Foo f3=f1+f2;这行代码中并没有执行赋值操作

(1)对于内置类型变量(如int,double,bool等),直接初始化与拷贝初始化差别可以忽略不计。

(2)对于类类型的变量(如string或其他自定义类型),直接初始化调用类的构造函数(调用参数类型最佳匹配的那个),拷贝初始化调用类的拷贝构造函数。

特别的,当对类类型变量进行初始化时,如果类的构造函数采用了explicit修饰而且需要隐式类型转换时,则只能通过直接初始化而不能通过拷贝初始化进行操作。

列表初始化

列表初始化是C++ 11 新引进的初始化方式,它采用一对花括号({})进行初始化操作。而在此之前,比如C++98/03 只有数组和POD类型才可以使用列表初始化。到了C++ 11,能用直接初始化和拷贝初始化的地方都能用列表初始化,而且列表初始化能对容器进行方便的初始化,所以在新的C++标准中,推荐使用列表初始化的方式进行初始化。

而在某些情况下,初始化的真实含义依赖于初始值时用的是花括号还是圆括号。代码如下

int main(void)
{vector<int>vec1(10);//vec1有10个元素,每个元素值为0vector<int>vec2{10};//vec2有1个元素,值为10vector<int>vec3(10, 1); // vec3有10个元素,每个元素值为1vector<int>vec4{ 10, 1 };// vec4有2个元素,值分别为10和1
}

如果使用圆括号,提供的值是用来构造对象的
如果使用花括号,表明我们相要列表初始化该对象,即尽可能把花括号中的值当成元素初始值来处理。,但是如果提供的值不能用来列表初始化,则考虑通过构造来进行初始化vector<string>vec5{10};由于花括号里的值与元素类型不同,不能进行列表初始化,所以将vec5有10个元素,每个元素进行默认初始化。

当用于内置类型的变量时,这种初始化形式还有一个重要的特点:如果使用列表初始化且初始值存在丢失信息的风险,则编译器将报错

int main(void)
{double d = 1.2345;int a(d), b = d;       //正确;虽然编译器不报错,但是会提示存在丢失信息的风险int x{ d }, y = { d };//错误;编译器会报错,因为从double转换到int存在丢失信息的风险。
}

默认初始值

  • 内置类型的初始值由定义的位置决定

    • 定义在任何函数体之外的变量被初始化为0
    • 定义在函数体内部的局部变量则未定义,如果试图拷贝或者以其他形式访问该变量,则会引发错误

    但是函数体内部的局部静态变量例外,如果局部静态变量没有显示的初始化,它将执行值初始化

    int global_a;//值为0
    short c;//值为0
    int main(void)
    {static int a;//值为0int b;//错误;未进行初始化
    }
    
  • 对于类类型,其默认初始值由类自己决定
    • 如果类中的数据成员在默认构造函数中进行了赋值,则默认初始化值优先使用默认构造函数的值
    • 如果在默认构造函数中没有赋值,但是该数据成员提供了类内初始值,则创建对象时,其默认初始值就是类内初始值,
    • 如果在默认构造函数中没有赋值且没有类内初始值,对于内置类型,则其值未定义,对于类类型,则对其进行默认初始化
class B {public:string str="123";
};
class A {public:A() {x = 1;}int x = 5;int y = 10;B b;
};
A global_a;
int main(void)
{A a;cout << global_a.x << " " << global_a.y << " " << global_a.b.str << endl;cout << a.x << " " << a.y << " " << a.b.str << endl;
}

参考

《C++ primer(第5版)》
C++11列表初始化(统一了初始化方式)
C++的各种初始化

C++变量初始化形式及其默认初始值相关推荐

  1. 未初始化数组的默认初始值

    在日常编程编写过程中,有时会new一个数组对象,但是在未赋值的情况下,不同类型的数组,默认初始值也是不同的.如下所示: char[] ch = new char[3];//默认\u0000 int [ ...

  2. 初始化、赋值、默认初始化、列表初始化、类内初始值、直接初始化与拷贝初始化

    文章目录 初始化和赋值的区别 什么是默认初始化? 列表初始化 列表初始化的使用场景 不适合使用列表初始化的场景 类内初始值 混用string对象和C风格字符串 数组与vector对象 关于vector ...

  3. java成员变量默认是_在Java语言中,String类型的成员变量的默认初始值是( )

    在Java语言中,String类型的成员变量的默认初始值是( ) 答:C.null 学生最主要的权利是() 答:受教育权 提倡教育要适合孩子的 "敏感期"的教育家是 答:蒙台梭利 ...

  4. java arraylist初始大小_Java - ArrayList默认初始值

    当您在Java中创建Integer类型的数组列表时,默认值是什么?我需要检查一个数组列表是否已满,然后我将获取数组的大小,然后获取最后一个索引处的值,并检查它是否为默认值.Java - ArrayLi ...

  5. Java未赋值变量的默认初始值

    在 Java 程序中,任何变量都必须经初始化后才能被使用.当一个对象被创建时,实例变量在分配内存空间时按程序员指定的初始化值赋值,否则系统将按下列默认值进行初始化: 数据类型 初始值 byte 0 s ...

  6. C语言 数组的初始化 数组不初始化会怎样 数组的默认初始值

    本程序用于测试:数组的初始化. (1)定义数组后必须要初始化,不要认为不初始化,系统就会自动初始化为O;如果不初始化,局部变量在栈上,各数组元素的值将是随机数; (2)数组初始化:程序员至少必须把数组 ...

  7. 使用公式给参数赋默认初始值

    目录: 1. 问题描述 2. 解决方案 3. 示例 1. 问题描述编辑 一般参数默认值都是固定的,但有时也需要动态的显示默认值,比如日期参数默认显示当前日期,甚至是需要根据当前日期计算出当前月的第一天 ...

  8. java 基本数据类型的默认初始值

    java语言中有8中基本数据类型,基本情况如下: 序号 数据类型 大小/位 封装类 默认值 可表示数据范围 1 byte(位) 8 Byte 0 -128~127 2 short(短整型) 16 Sh ...

  9. 局部变量和成员变量的初始值问题

    引言 大家都知道,在java中,成员变量是可以不用给初始值的,默认就有一个初始值.而局部变量,必须显示给予一个初始值,否则编译无法通过.大家在学习的时候,一般是直接把这个结论直接记下,很少去考虑原因. ...

  10. java默认数组值_数组元素默认的初始值都是什么

    在Java中,使用数组时,如果为数组分配了内存空间,但是没有为数组元素指定初始值,系统会自动为数组元素指定初始值.数组元素的初始值与数组的数据类型有关,对于不同数据类型的数组,其数组元素的初始值是不一 ...

最新文章

  1. powerbi learning: look up table and data table
  2. Hibernate4.x之映射关系--双向1-n
  3. Function接口练习之按照指定要求操作数据
  4. 腾讯万亿级Elasticsearch应用及优化解密
  5. 会动的图解 | 既然IP层会分片,为什么TCP层也还要分段?
  6. html css 圆形按钮 仿uc,10款基于jquery的web前端动画特效
  7. 无法在web服务器上启动调试。调试失败,因为没有启用集成windows身份验证
  8. 如何将html的按钮做成圆角,HTML 圆角按钮的实现备忘
  9. 大班如果我有机器人教案_大班科学机器人教案
  10. 前端如何实现商品规格
  11. 揭开中本聪的真实身份?这只是杀毒软件之父疯狂人生中的一件小事
  12. DBeaver无法连接SQL Server
  13. 红外图像非均匀矫正——一点矫正
  14. 截取图片DEMO. JAVA Windows FFmpeg
  15. oracle 远程访问配置,C#教程之Oracle 远程访问配置
  16. 修改userdata的分区大小
  17. 一键登录只需1秒,赶紧了解一下
  18. Android Launcher 入门
  19. pandas数据分析给力教程【完整版】(五)
  20. 关于“允许USB调试弹框”

热门文章

  1. 华为云CDN网站加速配置
  2. 如何将mp3合并在一起?
  3. day7 局部变量和封装
  4. java ligerui_[Java教程]ligerUI
  5. CSS绝对定位、相对定位
  6. 华为云notebook在线解压压缩包问题
  7. Android Sunflower 带您玩转 Jetpack
  8. oracle的dmp文件导入mysql_Oracle 数据库导入导出 dmp文件
  9. Android O版本power按键锁屏亮屏流程
  10. linux centos7 安装svn,linux centos7安装svn并配置同步更新web项目