C++的初始化有很多方式:默认初始化,值初始化,直接初始化,拷贝初始化,列表初始化。这些方式之间有什么区别与联系呢?我们一一来看。
默认初始化
默认初始化是指定义变量时没有指定初值时进行的初始化操作。例如int a; Sales_data myData;等等。这些变量被定义了而不是仅仅被声明(因为没有extern关键字修饰),而且没有显式的赋予初值。特别的,如果采用动态分配内存的方式(即采用new关键字)创建的变量,不加括号时(如int *p=new int;)也是默认初始化,加了括号(如int *p=new int())为值初始化。变量的值与变量的类型与定义的位置有关系。
(1)对于内置类型变量(如int,double,bool等),如果定义在语句块外(即{}外),则变量被默认初始化为0;如果定义在语句块内(即{}内),变量将拥有未定义的值。
(2)对于类类型的变量(如string或其他自定义类型),不管定义于何处,都会执行默认构造函数。如果该类没有默认构造函数,则会引发错误。因此,建议为每个类都定义一个默认构造函数。
int a;
Sales_data myData;
vector<string> svec;
string s;
值初始化
值初始化是值使用了初始化器(即使用了圆括号或花括号)但却没有提供初始值的情况。例如,
int *p=new int();
// 对于vector而言,只提供了vector对象容纳的元素数量而略去初始值
vector<string> svec(10);
vector<int>ivec(10);
等等都是典型的值初始化方式。注意,当不采用动态分配内存的方式(即不采用new运算符)时,写成int a();是错误的值初始化方式,因为这种方式声明了一个函数而不是进行值初始化。如果一定要进行值初始化,必须结合拷贝初始化使用,即写成int a=int();值初始化和默认初始化一样,对于内置类型初始化为0,对于类类型则调用其默认构造函数,如果没有默认构造函数,则不能进行初始化。
直接初始化与拷贝初始化
直接初始化与拷贝初始化对应,其内部实现机理不同。
直接初始化是指采用小括号的方式进行变量初始化(小括号里一定要有初始值,如果没提供初始值,那就是值初始化了!)。
int a(12);
Sales_data myData(para);
vector<int> ivec(ivec2);//直接初始化对于vector容器而言,仅支持这样的形式
string s("123456");
注意 vector<int> ivec(10)是值初始化,并不是直接初始化。
拷贝初始化是指采用等号(=)进行初始化的方式。
int a=12;
Sales_data myData=para;
vector<int> ivec=ivec2;
string s=string("123456");
拷贝初始化看起来像是给变量赋值,实际上是执行了初始化操作,与先定义再赋值本质不同。
(1)对于内置类型变量(如int,double,bool等),直接初始化与拷贝初始化差别可以忽略不计。
(2)对于类类型的变量(如string或其他自定义类型),直接初始化调用类的构造函数,拷贝初始化调用类的拷贝构造函数。
直接初始化不一定要调用拷贝构造函数,而拷贝初始化一定要调用拷贝构造函数。特别的,当对类类型变量进行初始化时,如果类的构造函数采用了explicit修饰而且需要隐式类型转换时,则只能通过直接初始化而不能通过拷贝初始化进行操作。
列表初始化
列表初始化是C++ 11 新引进的初始化方式,它采用一对花括号(即{})进行初始化操作。能用直接初始化和拷贝初始化的地方都能用列表初始化,而且列表初始化能对容器进行方便的初始化,因此在新的C++标准中,推荐使用列表初始化的方式进行初始化。
int a{12};
string s{"123"};
//对vector容器而言
vector<int> vec{1,2,3};
vector<string> v1{"a","an","the"};
这里一定要注意,列表初始化使用的是花括号而不是圆括号!
创建指定数量的元素
还可以用vector对象容纳的元素数量和所有元素的统一初始值来初始化vector对象:
vector<int> ivec(10,-1);//10个int类型的对象,每个对象都被初始化为-1
vector<string> svec(10,"hi!");//10个string对象,每个都是"hi!"
通常通过花括号或圆括号来区分初始化含义
vector<int> v1(10);//v1有10个元素,每个都为0
vector<int> v2{10};//v2有1个元素,为10
vector<int> v3(10,1);//v3有10个元素,每个都是1
vector<int> v4{10,1};//v4有2个元素,值分别是10和1
另一方面,如果初始化使用了花括号的形式但是提供的值又不能用来列表初始化
vector<string> v5{"hi"};//列表初始化,v5有1个元素
vector<string> v6("hi");//错误,不能用字符串字面值来构建vector对象,即没有提供数量
vector<string> v7{10};//提供的值补鞥能用来列表初始化,所以是值初始化,v7有10个默认初始化的元素
vector<string> v8{10,"hi"};//不能列表初始化,v8有10个值为"hi”的元素
但一般使用vector都是默认初始化后,再用成员函数push_back添加元素。