- C++11中,列表初始化可以用于任何类型对象的初始化
1){}前面的 = 可有可无:
int a {12};
int a = {12}; // 两种方式等同
- new操作符等可以用()初始化的地方也可以换作列表初始化,堆上动态分配的数组也可以使用初始化列表来初始化。
int* a = new int(10);
int* a = new int {10}; // 两种方式等同
int* b = new int[3] { 1, 2, 3}; // 可用列表初始化动态分配的空间!
// 初始化struct
struct A
{
int x;
int y;
} a = { 123, 456};
- 列表初始化的使用细节
- 不能初始化有private或protected的非静态数据成员的class
struct Foo
{
int x;
int y;
protected:
int z;
};
Foo foo{123, 456, 789}; // error
struct Foo
{
int x;
int y;
protected:
static int z; // z is protected but it's static
};
Foo foo{123, 456}; // OK
2)不能初始化有基类的class。有继承关系的class初始化的过程是自顶向下,先调用基类的构造函数来构造父类的成员,然后在此基础上再把自己创建出来。而每个对象在生命周期内只能被初始化一次。
struct Base {};
struct Foo : public Base
{
int x;
double y;
};
Foo foo{123 ,456.0}; // error
- 不能初始化有虚函数的class或struct;
但是以上的解决方法是:自定义一个构造函数即可, 列表初始化只要有对应的构造函数即可!!
struct Foo
{
int x;
int y;
Foo(int i, int j, int k) {}
protected:
int z;
};
Foo foo{123, 456, 789}; // OK
struct Foo
{
int x;
int y;
Foo(int i, int j) {}
protected:
int z;
};
Foo foo{123, 456}; // OK
- std::initializer_list: 轻量级类模板
- 可用来接收传递同类型的数据集合:
class FooVector
{
public:
FooVector(std::initializer_list<int> list)
{
for(auto it = list.begin(); it != list.end(); ++it)
content_.push_back(*it);
}
private:
std::vector<int> content_;
}
FooVector foo_1{1, 2, 3, 4, 5, 6}; // OK
void func(std::initializer_list<int> list)
{
for (auto it = list.begin(); it != list.end(); ++it)
std::cout << *it << std::endl;
}
func({1, 2, 3, 4, 5}); // OK
- 接收任意长度的初始化列表,但必须是同类型T
3) 三个成员接口:begin(), end(), size()
- 只能整体初始化或赋值,遍历只能通过begin() 和end(),遍历时取得的迭代器是只读的,无法修改std::initializer_list中单个的某个值。
std::initializer_list<int> list;
int n = list.size(); // n == 0, list此时为空
list = { 1, 2 ,3 ,4, 5}; // 可整体赋值
int n = list.size(); // n == 5;
- std::initializer_list只保存列表中元素的引用, 不保存元素的拷贝,因此对于比较大的对象列表也很高效,但是因为是引用所以有些地方需要注意!
std::initializer_list<int> func(void)
{
int a = 1, b = 2;
return { a, b}; //编译通过但是运行结果未知!!
}
//应该的做法:
std::vector<int> func(void)
{
int a = 1, b = 2;
return { a, b };
}
- 列表初始化可防止类型收窄