【C++11】初始化列表用法
初始化列表
- 在C++98时,若想使用花括号“{}”对数组元素进行初始化,只能进行形如:
int arr[5] = {0};
int arr[] = {1, 2, 3, 4} ;
但一些自定义类型(包括标准库中形如vector这样的容器)是不被允许的,在C++11中增加了该功能,这种初始化的方法被称为“初始化列表”
#include <vector>
#include <map>
using namespace std;
int a[] = {1, 3, 5}; // C++98通过,C++11通过
int b[] {2, 4, 6}; // C++98失败,C++11通过
vector<int> c{1, 3, 5}; // C++98失败,C++11通过
map<int, float> d = {{1, 1.0f}, {2, 2.0f} , {5, 3.2f}}; // C++98失败,C++11通过
// 编译选项:g++ -c -std=c++11 3-5-1.cpp
从C++11开始,以下几种形式的初始化得到允许:
//“=”加上赋值表达式
int a = 3+4;
//"=" 加上花括号初始化列表
int a = {3+4};
//圆括号的表达式列表
int a(3+4);
//花括号的初始化列表
int a{3+4}
- 是否只有内置类型才支持初始化列表?答案是:否,自定义类型也可以
方法:include <initializer_list>头文件
#include <vector>
#include <string>
using namespace std;
enum Gender {boy, girl};
class People
{
public:
//使people类可以通过初始化列表的方式来初始化私有成员data
//看起来就像是可以放任意数量的pair<string, Gender>作为构造函数的参数
People(initializer_list<pair<string, Gender>> l)
{
// initializer_list的构造函数
auto i = l.begin();
for (;i != l.end(); ++i)
data.push_back(*i);
}
private:
vector<pair<string, Gender>> data;
};
People ship2012 = {{"Garfield", boy}, {"HelloKitty", girl}};
// 编译选项:g++ -c -std=c++11 3-5-2.cpp
- 进阶用法:重载[]和=来实现批量修改数组中的值
#include <iostream>
#include <vector>
using namespace std;
class Mydata
{
public:
Mydata & operator [] (initializer_list<int> l)
{
//重载[],将初始化列表的数据写到idex数组中
for (auto i = l.begin(); i != l.end(); ++i)
idx.push_back(*i);
//因为Mydata重载了"[]"后,还需要与"="进行重载,故需要return *this
return *this;
}
Mydata & operator = (int v)
{
if (idx.empty() != true)
{
//下标指中的位置,
for (auto i = idx.begin(); i != idx.end(); ++i)
{
//动态扩容存放数据的d数组,预防index超出d的容量
d.resize((*i > d.size()) ? *i : d.size());
//在idx所有存放的下标中,作为d的下标,将d中下标为Idx的位置的值改为v
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;
d[{1, 4, 5, 8}] = 4;
d.Print(); // 4 7 7 4 4 0 0 4
}
// 编译选项:g++ -std=c++11 3-5-4.cpp
- 如果初始化列表作为返回值,通常会构造出临时变量
//将构造临时变量vector<int>{1,3}并返回
vector<int> Func() { return {1, 3}; }
//采用const & 作为返回修饰符时,获得的是临时变量的引用,效果与返回一个字面值常量(如return "hello world";)相同
const vector<int>& Func1() { return {3, 5};}
使用列表初始化还有一个最大优势是可以防止类型收窄
- 一般类型收窄是指造成数据变化或精度丢失的隐式类型转换,在C++11中,使用了初始化列表后编译器会检查是否发生了类型收窄。
const int x = 1024;
const int y = 10;
char a = x; // 收窄,但可以通过编译
char* b = new char(1024); // 收窄,但可以通过编译
char c = {x}; // 收窄,无法通过编译
char d = {y}; // 可以通过编译
unsigned char e {-1}; // 收窄,无法通过编译
float f { 7 }; // 可以通过编译
int g { 2.0f }; // 收窄,无法通过编译
float * h = new float{1e48}; // 收窄,无法通过编译
float i = 1.2l; // 可以通过编译
// 编译选项:clang++ -std=c++11 3-5-5.cpp
ps:初始化列表是C++中唯一可以防止类型收窄的初始化方式
2022年12月6日

浙公网安备 33010602011771号