系列文章目录
提示:这里是系列文章的专栏
提示:以下是文章目录哦!
文章目录
目录
[1. C++98 初始化的痛点(对比引出 C++11)](#1. C++98 初始化的痛点(对比引出 C++11))
[2. C++11 统一列表初始化 {}(全场景代码 + 逐行注释)](#2. C++11 统一列表初始化 {}(全场景代码 + 逐行注释))
[2.1 内置类型初始化](#2.1 内置类型初始化)
[2.2 结构体 / 类初始化](#2.2 结构体 / 类初始化)
[2.3 STL 容器初始化](#2.3 STL 容器初始化)
[2.4 new + {} 动态内存初始化](#2.4 new + {} 动态内存初始化)
[2.5 直接列表初始化 {} / 拷贝列表初始化 ={}](#2.5 直接列表初始化 {} / 拷贝列表初始化 ={})
[案例 1:无 explicit 的多参构造(C++11)](#案例 1:无 explicit 的多参构造(C++11))
[案例 2:explicit 修饰多参数构造(重点)](#案例 2:explicit 修饰多参数构造(重点))
[1.C++98 旧标准](#1.C++98 旧标准)
[2.C++11 及以后新标准(考点)](#2.C++11 及以后新标准(考点))
[3. 列表初始化的强大优势:禁止窄化转换](#3. 列表初始化的强大优势:禁止窄化转换)
[4. std::initializer_list({} 批量初始化的底层)](#4. std::initializer_list({} 批量初始化的底层))
[4.1 基本用法(逐行注释)](#4.1 基本用法(逐行注释))
前言
提示:这里可以添加本文要记录的大概内容:
我们已经完整结束 C++ 数据结构(vector/list/map/set 等 STL 容器)全部内容,在容器练习中大家大概率遇到一个疑惑:为什么vector<int> v={1,2,3,4};这种花括号直接初始化写法,C++98 不支持、C++11 却可以直接使用?这正是我们开启 C++11 新特性学习的第一个切入点 ------统一列表初始化(List Initialization)
C++98/03 历经十余年使用,初始化语法长期处于割裂状态:数组、普通结构体才能用{}初始化,内置类型靠=/()、自定义类依赖构造函数()、STL 容器初始化需要逐个 push_back,语法杂乱、写法不统一还容易出现窄化转换隐患。2011 年 ISO 正式落地 C++11 标准,首当其冲解决的就是初始化混乱问题:推出全类型通用的 {} 列表初始化 ,再通过std::initializer_list支撑 STL 容器批量初始化,彻底实现「万物皆可大括号初始化」
作为 C++11 最基础、日常编码最高频的特性,列表初始化是后续学习右值引用、移动语义、可变参数模板、emplace 系列接口的前置铺垫。本文会从C++98 初始化痛点→C++11 列表初始化语法→initializer_list 原理→容器实战→手写模拟容器层层拆解,结合课件全部示例代码,打通从基础变量到 STL 容器的初始化全链路,帮大家彻底吃透 C++11 初始化核心
提示:以下是本篇文章正文内容
1. C++98 初始化的痛点(对比引出 C++11)

弊端总结:
- 语法不统一
- 类不能直接
{}初始化 - 容器不能批量初始化
2. C++11 统一列表初始化 {}(全场景代码 + 逐行注释)
C++11 规则:任何对象都可以用
{}初始化,=可写可不写
但是以上这句话,有些不太准确,我们在2.5来仔细讲讲
2.1 内置类型初始化

运行结果如下:

所以以上初始化的方法我们直接记住写法2就行了
2.2 结构体 / 类初始化
cpp
#include <iostream>
using namespace std;
// 结构体(聚合类型)
struct Point
{
int x;
int y;
};
// 类
class Date
{
public:
// 构造函数
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
// 打印函数
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
// 1. 结构体 C++11 列表初始化
Point p{ 10, 20 }; // 直接 {},不需要 =
cout << p.x << " " << p.y << endl;
// 2. 类 C++11 列表初始化(C++98 做不到!)
Date d1{ 2025, 1, 1 }; // 直接调用构造函数
d1.Print();
Date d2 = { 2024, 12, 25 }; // 加 = 也可以
d2.Print();
return 0;
}
运行结果如下:

可见不管是内置类型还是自定义类型都是可以用**"{}"**来进行初始化的
2.3 STL 容器初始化
cpp
#include <iostream>
#include <vector>
#include <map>
#include <string>
using namespace std;
int main()
{
// vector 直接用 {} 批量初始化
vector<int> v{ 1,2,3,4,5 };
// 遍历打印
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
// map 嵌套 {} 初始化
map<string, string> dict{
{"apple", "苹果"},
{"book", "书"},
{"student", "学生"}
};
// 遍历 map
for (auto& kv : dict)
{
cout << kv.first << " : " << kv.second << endl;
}
return 0;
}
运行结果如下:

这里顺便讲讲map 的 {} 初始化 :
第一步:回忆 map 到底存的是什么?
map<string, string> 里面存的不是两个独立字符串,而是:

pair 是键值对结构体:

所以:map 存的是一堆 pair,map 的 {} 初始化 = 批量插入 N 个 pair
第二步:一层一层拆大括号

拆第一层:最外层 {...}

这是一个 initializer_list< pair<string,string> > → 传给 map 的构造函数
拆第二层:里面每一个 {...}

发生隐式类型转换:

所以整段代码:

等价于:

2.4 new + {} 动态内存初始化

运行结果如下(注意一下写法):

2.5 直接列表初始化 {} / 拷贝列表初始化 ={}
拷贝列表不能用 explicit 构造函数隐式转换,直接列表可以,
=决定初始化种类,explicit 只拦截带 = 的拷贝列表初始化


案例 2:explicit 修饰多参数构造(重点)
explicit关键字针对多参数构造也是一样的,进制隐式类型转换
案例 1:无 explicit 的多参构造(C++11)

案例 2:explicit 修饰多参数构造(重点)

分版本规则细化(上课总结)
1.C++98 旧标准
- explicit仅对单参数构造生效;
- 多参数构造:
Test t={1,2};直接编译报错,天生不能隐式转换 ,explicit Test(int,int)写了等于没写
2.C++11 及以后新标准(考点)
Test t{1,2}(不带 =,直接列表):无论是否 explicit,全部合法,直接调用构造Test t={1,2}(带 =,拷贝列表):explicit 修饰后报错,不加 explicit 则允许隐式转换Test t(1,2)(圆括号):永远显式调用,explicit 不影响
3. 列表初始化的强大优势:禁止窄化转换
窄化转换:把大范围类型赋值给小范围类型(double → int,int → char 等)
C++98 允许,会隐式丢失数据; C++11 {} 初始化直接禁止,编译报错!更安全!

4. std::initializer_list({} 批量初始化的底层)
4.1 基本用法(逐行注释)

5.本章总结
- C++11 用
{}统一所有类型初始化,语法简洁、安全 {}会禁止窄化转换,避免隐式数据丢失std::initializer_list是容器批量初始化的底层支撑- 所有容器都提供了
initializer_list版本构造 + 赋值 - 自己写类 / 容器时,加一个
initializer_list构造,就能支持{}初始化
