初始化列表的概念及使用 C++98中,标准允许使用花括号”{}”对数组元素进行统一的集合初始值设定。比如:
1 2 int arr[5] = {0}; int arr[] = {1,2,3,4};
C++11中,这种初始化的方法,被扩展到了集合(列表)中。
总结初始化方法如下: 1) 等号加上赋值表达式,如 int a = 3+4; 2) 等号 加上花括号的 初始化列表, 如 int a = {3+4}; 3) 圆括号式的表达式列表(expression list), 如 int a = (3+4); 4) 花括号式的初始化列表 , 如 int a{3+4}
其中,第3、4中方式也可用于获取堆内存 new操作符中,如下:
1 2 int * i = new int(5); double *d = new double(1.5f);
标准模板库中容器对初始化列表的支持源自这个头文件中initialize_list的类模板的支持。 只需要包含这个头文件,并且声明一个以initialize_list模板类为参数的构造函数,同样可以使得自定义的类使用列表初始化。
利用初始化列表,重载operator[],operator= 以及使用辅助的数组。例子如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <iostream> #include <vector> #include <initializer_list> using namespace std; class Mydata{ public: Mydata& operator[](initializer_list<int> l){ for(auto i=l.begin();i!=l.end();++i) idx.push_back(*i); return *this; } Mydata& operator=(int v){ if(idx.empty()!=true) { for(auto i = idx.begin();i!=idx.end();++i) { d.resize((*i>d.size())?*i:d.size()); d[*i-1] = v; } idx.clear(); } return *this; } void print(){ for(auto i=d.begin();i!=d.end();++i) cout<<*i<<" "; cout<<endl; } private: vector<int> idx; //辅助数组,用于记录index vector<int> d; }; int main(){ Mydata d; d[{2,3,5}] = 7; //将第2,3,5位设为7 d[{1,4,5,8}] = 4; //第1,4,5,8位设为4 d.print(); //4 7 7 4 7 0 0 4 }
此外,初始化列表还可以用于函数返回的情况,但是返回一个初始化列表,通常会导致构造一个临时变量
1 2 3 vector<int>Func(){ return {1,3}; }
防止类型收窄 使用列表初始化还有一个最大优势是 可以防止类型收窄。
类型收窄 一般是指一些可以使得数据变化或者精度丢失的隐式类型转换。
可能导致 类型收窄的典型情况如下:
以浮点数隐式地转换为整型 比如: int a = 1.2
从高精度的浮点数转化为低精度的浮点数,比如: 从long double 隐式地转为 double。或者从double 转为 float。 这种精度降低,都可以视为类型收窄
从整型转为浮点数。如果整型数大到无法使用浮点数精确表达,也可以视为类型收窄
从整型,转为较低长度地整型。 比如:unsigned char = 1024; 1024是不能被8位地unsigned char 容纳的
使用初始化列表,是不能容许类型收窄的情况出现的。会编译通不过。
使用自定义初始化列表 示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Warriors { public: Warriors(const initializer_list<string>& members) { for (auto& data : members) { players.emplace_back(data); } } vector<string> players; void print() { for (auto itm : players) std::cout << itm << endl; } };