摘自:深入应用C++11:代码优化与工程级应用
在C++98/03中存在着种类繁多的初始化方式。C++11为了统一初始化方式,提出了列表初始化的概念。
#1.3.1 统一的初始化
在C++98/03中,只有普通数组和POD类型可以使用初始化列表。
【POD类型】plain old data类型,即可以直接用memcpy复制的对象。如:
int i_arr[3]={1,2,3};
struct a
{
int x;
int y;
}a={1,2};
在C++11中,初始化列表可以用于任何对象的初始化。
- 对普通数组和POD类型进行初始化。
- 之前使用()调用构造函数,可以使用初始化列表替换。
- 在堆上分配的动态数组,可以使用初始化列表。
- 初始化列表可以直接用在函数返回值上。 如:
struct Foo
{
int x;
int y;
};
int *a=new int{1};
double p=double{p};
int *arr=new int[4]{1,2,3,4};
Foo function()
{
return {1,2};
}
在初始化时,{}前面的=书写与否不会影响初始化的行为。
#1.3.2 列表初始化的使用细节
对于一个聚合类型,使用初始化列表相当于对其中的每个元素分别赋值;
对于非聚合类型,需要先定义一个构造函数,使用初始化列表将调用其构造函数。
【聚合类型】的定义:
- 类型是一个普通数组。
- 类型是一个类(class、struct、union)且
- 无用户自定义的构造函数。
- 无private和protected的非静态数据成员
- 无基类;
- 无虚函数;
- 不能有直接初始化的非静态数据成员(GCC中可以)
聚合类型的定义并非递归的,当一个类的非静态成员是非聚合类型时,这个类也可能是聚合类型。如:
struct ST
{
int x;
double y;
private:
int z;
};
struct Foo
{
ST st;
int x;
double y;
};
Foo foo{{},1,2.5};
其中{}可以用来调用无参构造函数。
#1.3.3 初始化列表
##任意长度的初始化列表
为了让类的构造函数(或者其他函数)拥有任意长度初始化的能力,C++11在stl中引入了std::initialzer_list这个轻量级的模板。如:
class FooVector
{
public:
FooVector(std::initializer_list<int> list)
{
for(auto i:list)
{
cout<<i<<endl;
}
}
};
FooVector fooVector{1,2,3,4,5};
void Function(std::initializer_list<int> list)
{
for(auto i:vect)
{
cout<<i<<endl;
}
return ;
}
Function({1,2,3,4,5});
##std::initialzer_list的一些细节
- 它是一个轻量级的容器类型,iterator、size()、begin()、end();
- std::initialzer_list可以接受任意长度的初始化列表,但元素类型必须是相同类型T;
- std::initialzer_list的传递和赋值的效率高,它内部只存储了列表中元素的引用(不需要进行值拷贝);这是它与std:vector的重要区别;
- 因为std::initialzer_list的元素可能是保存在函数栈中的局部变量,因此std::initialzer_list不适合做函数的返回值;而应使用std::vector。
- std::initialzer_list只能被整体初始化或赋值。
std::initializer_list<int> func1()
{
int a=1,b=2;
return {a,b};//a、b在返回时没有被拷贝,错误的写法
}
std::vector<int> func2()
{
int a=1,b=2;
return {a,b};
}
#1.3.4 防止类型收窄
【类型收窄】导致数据内容发送变化或者精度丢失的隐式类型转换。如:
- 浮点数隐式转换为整型数;
- 高精度浮点数隐式转换为低精度浮点数;
- 整型数转换为浮点数,且超出了浮点数的表示范围;
- 长整型数转换为短整型数
在C++98/03中,编译器对于类型收窄不会报错;
在C++11中,列表初始化检查类型收窄的情况,并报警告或错误。如:
int a=1.1; //OK
int b={1.1}; //ERROR
const int x=1024;
const int y=1;
char c={x}; //ERROR
char d={y}; //OK
float ff=1.2;
float fd={1.2};
在fd的初始化没有引起类型收窄,但是VS2013中会报错,而gcc4.8中不会报错。