
🌈个人主页:聆风吟_
🔥系列专栏:C++11新章
🔖少年有梦不应止于心动,更要付诸行动。
文章目录
- [一、背景:C++98传统的 {}](#一、背景:C++98传统的 {})
- 二、什么是列表初始化?
- 三、基础用法示例
-
- [3.1 基础变量初始化](#3.1 基础变量初始化)
- [3.2 数组初始化](#3.2 数组初始化)
- [3.3 动态分配内存](#3.3 动态分配内存)
- 四、进阶用法示例
-
- [4.1 结构体初始化](#4.1 结构体初始化)
- [4.2 类初始化](#4.2 类初始化)
- [4.3 STL 容器初始化](#4.3 STL 容器初始化)
- [六、列表初始化的 4 大好处](#六、列表初始化的 4 大好处)
- 📝全文总结
一、背景:C++98传统的 {}
C++98中一般数组和结构体可以用 {} 进行初始化。
cpp
#include <iostream>
using namespace std;
struct Point
{
int _x;
int _y;
};
int main()
{
// 变量:=
int x = 10;
// 数组:{}
int array1[] = { 1, 2, 3, 4, 5 };
int array2[5] = { 0 };
// 结构体:{}
Point p = { 1, 2 };
return 0;
}
二、什么是列表初始化?
在 C++11 之前,初始化方式特别乱:
-
变量用
= -
数组用
{} -
对象用
() -
容器没法直接批量赋值
C++11 直接统一:不管什么类型,全都能用 {} 初始化 ,这就叫列表初始化。
语法格式(两种写法完全等价,都可以用):
cpp
类型 变量名{值1, 值2, ...}; // 推荐写法
类型 变量名 = {值1, 值2, ...};
📌小贴士:
{}初始化过程中可以省略=
三、基础用法示例
3.1 基础变量初始化
内置类型(int、double、bool 等)直接用 {} 赋值,语法更统一。
cpp
#include <iostream>
using namespace std;
int main()
{
// C++98 传统写法
int a = 10;
double b = 3.14;
// C++11 列表初始化
int c{ 10 }; // 等价 int c = 10;
double d{ 3.14 }; // 等价 double d = 3.14;
bool e{ true }; // 等价 bool e = true;
cout << "c = " << c << endl;
cout << "d = " << d << endl;
cout << "e = " << e << endl;
return 0;
}
输出结果:
Plain
c = 10
d = 3.14
e = 1
3.2 数组初始化
cpp
#include <iostream>
using namespace std;
int main()
{
// C++98
int arr1[3] = { 1, 2, 3 };
// C++11 列表初始化(两种写法等价)
int arr2[3] = { 1, 2, 3 };
int arr3[]{ 1, 2, 3 }; // 自动推导长度为3
int arr4[5]{ 1, 2, 3 }; // 未赋值元素自动初始化为0
return 0;
}
3.3 动态分配内存
C++11 支持用 {} 初始化动态分配的对象:
cpp
#include <iostream>
using namespace std;
class Person
{
public:
Person(int a, string n) : age(a), name(n) {}
private:
int age;
string name;
};
int main()
{
// 动态int数组,初始化为{1,2,3}
int* arr = new int[3] {1, 2, 3};
// 动态对象初始化
Person* p = new Person{ 25, "王五" };
return 0;
}
四、进阶用法示例
4.1 结构体初始化
cpp
#include <iostream>
using namespace std;
struct Point
{
int x;
int y;
int z;
};
int main()
{
// 列表初始化结构体
// 1. 完整初始化(给所有成员赋值)
Point d1 = { 2026, 1, 1 }; // 传统写法
Point d2{ 2026, 1, 1 }; // C++11 简写(推荐)
// 2. 部分初始化(没写的自动 = 0)
Point d3{ 2026 }; // year=2026, month=0, day=0
Point d4{ 2026, 1 }; // year=2026, month=1, day=0
// 3. 零初始化(全部 = 0)
Point d5{}; // year=0, month=0, day=0
return 0;
}
4.2 类初始化
列表初始化会自动调用匹配的构造函数:
cpp
#include<iostream>
#include <vector>
using namespace std;
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1)
:_year(year)
, _month(month)
, _day(day)
{
cout << "Date(int year, int month, int day) ------> 构造函数" << endl;
}
Date(const Date& d)
:_year(d._year)
, _month(d._month)
, _day(d._day)
{
cout << "Date(const Date& d) ------> 拷贝构造函数" << endl;
}
private:
int _year;
int _month;
int _day;
};
(1)C++98 传统初始化
cpp
// 传统圆括号初始化:直接调用构造函数
int main()
{
Date d0(2025, 1, 1);
return 0;
}
输出:
Plain
Date(int year, int month, int day) ------> 构造函数
(2)C++11 列表初始化
cpp
// 写法1:赋值形式的列表初始化
// 理论:{2026,1,1} → 构造临时对象 → 拷贝构造d1
// 编译器优化:直接构造d1,不会调用拷贝构造
Date d1 = { 2026, 1, 1 };
// 写法2:直接列表初始化(推荐)
// 最简洁,直接调用构造函数
Date d2{ 2026, 1, 1 };
输出:
cpp
Date(int year, int month, int day) ------> 构造函数
Date(int year, int month, int day) ------> 构造函数
(3)隐式类型转换
cpp
int main()
{
// 因为构造是全缺省,1个参数也能匹配
Date d3 = { 2025 }; // 列表初始化
Date d4 = 2025; // C++98 隐式类型转换
return 0;
}
输出:
cpp
Date(int year, int month, int day) ------> 构造函数
Date(int year, int month, int day) ------> 构造函数
(4)使用场景
cpp
int main()
{
vector<Date> v;
// 写法1:隐式转换构造
v.push_back(2026);
// 写法2:列表初始化构造(最常用)
v.push_back({ 2026, 1, 1 });
// 错误写法:
// v.push_back(2026, 1, 1); // 报错!push_back 只能传1个参数
return 0;
}
讲解:
-
push_back(2026):2026 隐式转换成 Date 对象,先构造,再拷贝进容器 -
push_back({2026,1,1}):{2026,1,1}直接构造 Date 临时对象,再拷贝进容器 -
为什么不能写
push_back (2026,1,1)?-
push_back 只能接收 1 个参数
-
三个 int 是 3 个参数,语法错误
-
必须用
{}打包成 一个对象 才能传入
-
输出:
cpp
Date(int year, int month, int day) ------> 构造函数
Date(const Date& d) ------> 拷贝构造函数
Date(int year, int month, int day) ------> 构造函数
Date(const Date& d) ------> 拷贝构造函数
4.3 STL 容器初始化
这是 C++11 最爽的地方,vector、map、string 等容器都能直接赋值:
cpp
#include <iostream>
#include <vector>
#include <map>
#include <string>
using namespace std;
int main()
{
// vector 直接批量赋值
vector<int> v{1, 2, 3, 4, 5};
// string 初始化
string s{"hello world"};
// map 键值对直接初始化
map<int, string> mp{{1, "one"}, {2, "two"}};
return 0;
}
六、列表初始化的 4 大好处
(1)统一所有初始化写法
不管是基础变量、数组、结构体、类、STL容器 ,全部只用 {} 一种写法 ,彻底告别 =、()、{} 混用的混乱规则。
cpp
#include <vector>
#include <string>
// 旧版 C++:初始化语法五花八门,极易记混
int a = 10; // 等号
int arr[] = { 1,2,3 }; // 数组
std::vector<int> v(2, 5); // 构造函数()
struct Point { int x, y; };
Point p = { 1, 2 }; // 结构体
// 现代 C++:全部统一用 {},一套规则走天下
int a{ 10 }; // 变量
int arr[]{ 1,2,3 }; // 数组
std::vector<int> v{ 2,5 }; // 容器
Point p{ 1,2 }; // 结构体
std::string s{ "hello" }; // 字符串
总结:列表初始化 {} 语法,统一所有类型初始化,代码风格更整洁,学习/记忆成本大幅降低。
(2)防止「窄化转换」,编译期拦截类型风险
禁止不安全的隐式缩窄转换 (比如 double → int、long → short),编译器直接报错,从根源避免数值丢失、精度错误。
📌小贴士
窄化转换:把大范围类型偷偷转成小范围(比如 double → int,long → char)。
cpp
// 1. 传统初始化:隐式缩窄转换,编译器不报错(埋坑!)
double pi = 3.1415;
int x = pi; // 合法!double 偷偷转 int,精度丢失
char c = 1000; // 合法!数值溢出,结果不可预期
// 2. 列表初始化:严格禁止缩窄转换,直接编译报错(安全!)
int x{pi}; // 报错:无法从 double 缩窄为 int
char c{1000}; // 报错:1000 超出 char 范围
float f{1.2345}; // 报错:double 不能缩窄为 float
总结:列表初始化 = 类型安全防火墙,所有不安全的隐式类型转换,都会在编译期被拦截,程序更健壮。
(3)容器直接批量赋值,告别繁琐 push_back
vector/map/list 等所有 STL 容器,直接用 {} 批量初始化/赋值 ,一行代码替代 N 行 push_back,代码极简直观。
cpp
#include <vector>
#include <map>
#include <iostream>
// 旧版:反复 push_back,代码冗长
std::vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
// 列表初始化:一行搞定,清晰优雅
std::vector<int> v2{1,2,3,4};
// map 同样支持,键值对直接批量写
std::map<std::string, int> score{
{"张三", 90},
{"李四", 85},
{"王五", 95}
};
总结:批量初始化容器,代码量锐减 80%,可读性、维护性直接拉满。
(4)空列表 {} 默认初始化,杜绝野值
对任意类型使用 {},编译器会自动执行「值初始化」:
-
基础类型(int/double/指针)→ 自动清零
-
自定义类型 → 调用默认构造
彻底杜绝未初始化变量导致的野值、崩溃、随机bug。
cpp
// 1. 传统定义:不初始化 = 随机野值(高危!)
int a; // 未初始化,值是内存垃圾(随机数)
double d; // 随机垃圾值
int* ptr; // 野指针,访问直接崩溃
// 2. 空列表 {}:强制默认初始化,全部安全清零
int a{}; // = 0
double d{}; // = 0.0
int* ptr{}; // = nullptr(空指针,安全)
std::vector<int> v{}; // 空容器
// 结构体/类同样适用
struct Point { int x,y; };
Point p{}; // x=0, y=0
总结:{} = 安全初始化兜底,再也不用担心忘记赋值导致的诡异bug。
📝全文总结
C++11列表初始化({}) 是对C++98繁杂初始化语法的大一统升级 ,它用一套极简、安全、统一的规则,彻底解决了传统初始化方式混乱、易错、不安全的痛点,是现代C++开发中首选、推荐、必备的初始化方式。它的核心价值可以浓缩为4句话:
- 语法大一统 :基础变量、数组、结构体、类对象、STL容器 ,所有类型统一用
{}初始化,代码风格极致简洁统一; - 类型更安全 :编译期严格禁止窄化转换(如double转int、大数转char),从源头拦截类型溢出、精度丢失的风险;
- 编码更高效 :STL容器(vector/map/list等)支持直接批量赋值,一行代码替代多行
push_back,大幅简化容器初始化; - 使用更稳健 :空列表
{}会自动对所有类型执行值初始化(基础类型清零、指针置nullptr、自定义类型调默认构造),彻底杜绝野值、野指针导致的程序bug。
简单来说:现代C++开发,初始化就用{},简洁、安全、不出错!
今天的干货分享到这里就结束啦!如果觉得文章还可以的话,希望能给个三连支持一下,聆风吟的主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是作者前进的最大动力!
