【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日

posted @ 2024-08-03 11:59  刘民心  阅读(59)  评论(0)    收藏  举报