C++11之列表初始化
列表初始化格式
1、C++98/03中的列表初始化格式:
int arr_int[3] = { 1, 2, 3 };
long arr_long[] = { 4, 5, 6 };
struct A
{
int x;
int y;
};
A a = { 1, 2 };
2、C++11中的列表初始化格式:
int arr_int[3] = { 1, 2, 3 };
long arr_long[] = { 4, 5, 6 };
struct A
{
int x;
int y;
};
A a = { 1, 2 };
A b{3, 4}; //C++98/03 error.
列表初始化的使用条件
1、C++98/03标准中对于普通数组和POD类型可以直接使用列表初始化;
2、C++11标准中对于普通数组和聚合类型可以直接使用列表初始化;
3、C++11标准中对于非聚合类型可以通过自定义构造函数的方式使用列表初始化。
// 对于非聚合类型可以通过自定义构造函数的方式使用列表初始化
class A
{
public:
ST(int m, double n, int p) : a(i), b(j), c(k) {}
int a;
double b;
virtual void func(){}
private:
int c;
};
A a { 1, 2.5, 2 };//C++11 ok
注意:POD类型是聚合类型的子集。
POD类型的定义
概念
简而言之,一个类或结构体通过二进制拷贝后还能保持其数据不变,那么它就是一个POD类型。
也就是说,能用memset/memcpy 等函数进行操作的类、结构体就是 POD 类型的数据。
特征
1、is_trival(平凡的)
条件:
如果一个类或者结构体的构造/析构函数、拷贝/移动构造函数、拷贝/移动运算符要么由编译器自动生成,要么被C++11的default修饰,且不能有 虚函数 和 虚基类,则它是平凡的。
判定:
使用std::is_trivial::value 来判断是否“平凡”。
2、is_standard_layout(布局要有序)
条件:
1、普通成员(非静态成员)有相同的访问级别;
2、第一个成员必须是当前类的;(不能是其他类型的成员子对象)
3、只要有父类,普通成员只能在其中一个类中,不可分散;(普通成员需要集中到某一个类中定义)。
判定:
使用std::is_standard_layout::value来判断是否“布局有序”。
参考:
1、https://www.cnblogs.com/zzyoucan/p/3918614.html
2、https://zhuanlan.zhihu.com/p/45545035
聚合类型的定义
1、类型是一个普通数组;
2、类型是一个类(class\struct\union),且
a、无用户自定义的构造函数;
b、无私有或保护的非静态数据成员;
c、无基类;
d、无虚函数;
e、不能有在声明时使用{}或=直接初始化的非静态数据成员。
注意:
聚合类型的定义并非递归的。即当一个类的非静态成员是非聚合类型时,这个类也有可能是聚合类型。
struct A
{
int x;
double y;
private:
int z;
};
A a { 1, 2.5, 1 }; // error, 非静态成员的访问属性不同
struct B
{
A a;
int x;
double y;
};
B b{ {}, 1, 2.5 }; // OK, 对于非聚合类A的初始化相当于使用无参构造函数
任意长度的初始化列表
概念:
通过给自定义类型增加一个 以std::initializer_list为参数的 构造函数,让它拥有任意长度初始化的能力。
class Map
{
public:
Map(std::initializer_list<map<int, int>::value_type> list)
{
for (auto it = list.begin(); it != list.end(); ++it)
{
_data.insert(*it);
}
}
private:
std::map<int, int> _data;
};
Map map_ = { { 1, 2 }, { 3, 4 }, { 5, 6 } };
std::initializer_list
1、是一个轻量级的容器类型;
2、std::initializer_list可以接收任意长度的初始化列表,但要求元素必须是同种类型 T(或可转换为 T);
3、它有 3 个成员接口:size()、begin()、end();
4、它只能被整体初始化或赋值。