目录
- 一、 一切皆可 `{}`
- 二、 自定义类型,自动调用构造函数
- 三、 幕后操作:`std::initializer_list`
- 四、 玩转 STL 容器:告别繁琐的 push_back
- 总结
在 C++11 之前,初始化一个变量或对象的方式五花八门:等号赋值、括号传参、大括号给数组赋初值……不仅繁琐,还容易让人记混。C++11 带着“大一统”的使命走来,彻底改变了这一切。
在 C++98 中,标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。比如int array1[] = {1, 2, 3};或是给结构体赋值Point p = {1, 2};。
但是到了 C++11,这种大括号{}(初始化列表)的使用范围被极大地扩大了,使其可用于所有的内置类型和用户自定义的类型。这就是我们今天要聊的——统一列表初始化。
一、 一切皆可{}
在 C++11 中,使用初始化列表时,可添加等号(=),也可不添加。这种语法不仅适用于基础变量,连数组和new表达式也能完美适配。
// 基础变量初始化,可以不要等号!intx1=1;intx2{2};// C++11 新玩法// 数组初始化,同样可以省去等号intarray1[]{1,2,3,4,5};intarray2[5]{0};// 全部初始化为0// 自定义结构体structPoint{int_x;int_y;};Point p{1,2};// C++11 中列表初始化也可以适用于 new 表达式中int*pa=newint[4]{0};二、 自定义类型,自动调用构造函数
对于类(Class)对象,C++11 同样支持这种写法。创建对象时也可以使用列表初始化方式调用构造函数初始化。
假设我们有一个Date类:
classDate{public:Date(intyear,intmonth,intday):_year(year),_month(month),_day(day){cout<<"Date(int year, int month, int day)"<<endl;}private:int_year;int_month;int_day;};intmain(){Dated1(2022,1,1);// old style:传统的括号传参// C++11 支持的列表初始化,这里会调用构造函数初始化Date d2{2022,1,2};Date d3={2022,1,3};return0;}以前给对象传参必须用小括号(),现在用大括号{}一样可以精准触发对应的构造函数,代码风格得到了史诗级的统一!
三、 幕后操作:std::initializer_list
为什么 C++11 的{}这么强大?当我们写下auto il = { 10, 20, 30 };时,这个等号右边的{}到底是个什么东西?
答案是:它的类型是std::initializer_list。
你可以把它理解为一个轻量级的、用来接收大括号列表的系统内置类型。它的出现,彻底盘活了 STL 容器的初始化。
四、 玩转 STL 容器:告别繁琐的 push_back
std::initializer_list一般是作为构造函数的参数。C++11 对 STL 中的不少容器就增加了以std::initializer_list作为参数的构造函数,这样初始化容器对象就更方便了。同时,它也可以作为operator=的参数,这样就可以用大括号赋值。
在没有 C++11 之前,初始化一个vector往往需要先定义,再一行行地push_back,十分痛苦。现在,一行代码搞定:
// 丝滑的容器初始化vector<int>v={1,2,3,4};list<int>lt={1,2};// 连 Map 这种键值对容器也能轻松驾驭// 这里 {"sort", "排序"} 会先初始化构造一个 pair 对象map<string,string>dict={{"sort","排序"},{"insert","插入"}};// 使用大括号对容器赋值v={10,20,30};总结
C++11 的统一列表初始化不仅仅是“少写一个等号”这么简单的语法糖。它通过扩展{}的使用范围,并引入底层的std::initializer_list,彻底打通了内置类型、自定义类和 STL 容器之间的初始化壁垒,让 C++ 的代码变得更加现代、简洁和优雅。