c++11列表初始化的核心是统一语法与窄化检查,而非仅数组初始化;它支持std::array、std::vector及聚合类型,禁止隐式窄化转换,推荐替代c风格数组和裸指针。

用 {} 初始化内置数组,但注意类型推导限制
直接用花括号初始化 C 风格数组是合法的,比如 int arr[] = {1, 2, 3};,C++11 保留了这个语法。但它不是“列表初始化”的全部含义——真正体现 C++11 列表初始化特性的,是 std::array 和 std::vector 的构造方式,以及对聚合类型的统一初始化规则。
常见错误是以为 int arr[3] = {1, 2, 3}; 是“C++11 新特性”,其实它早在 C++98 就支持;C++11 的关键是允许更严格的类型检查和禁止窄化转换(narrowing conversion)。
-
int arr[] = {1.5, 2, 3};→ 编译失败,因为1.5不能隐式转为int(窄化) -
int arr[3] = {};→ 全零初始化(值初始化),等价于int arr[3] = {0, 0, 0}; -
int arr[3] = {1};→arr[0]=1,其余元素零初始化,不是未定义行为
std::array 才是推荐的“现代数组”写法
std::array 是固定大小、栈上分配、零开销的容器,支持列表初始化且语义清晰。它的构造函数接受 std::initializer_list,也支持聚合初始化(C++17 起可省略模板参数)。
实操建议:
- 显式写法:
std::array<int> arr = {1, 2, 3};</int>(C++11 起合法) - C++17 起可简写:
std::array arr = {1, 2, 3};(类模板参数推导) - 不能写成
std::array<int> arr{1, 2, 3};</int>?可以,但注意:{}构造是直接初始化,和= {}拷贝初始化在某些场景有差异(如 explicit 构造函数),不过std::array的构造函数非 explicit,两者等效 - 错误示例:
std::array<int> arr = {1, 2, 3, 4};</int>→ 编译失败,元素数超限
动态数组别用 new int[]{...},优先选 std::vector
C++11 支持 new int[]{1,2,3} 这种“列表初始化 new 表达式”,但它返回裸指针,无长度信息、不自动释放、无法拷贝——几乎没人该这么写。
正确做法是用 std::vector:
-
std::vector<int> v = {1, 2, 3};</int>→ 最常用,安全、灵活、支持移动 -
std::vector<int> v{1, 2, 3};</int>→ 直接初始化,效果相同(除非重载了 initializer_list 构造函数并设为 explicit) - 避免:
int* p = new int[]{1,2,3};→ 忘记delete[]就泄漏;且sizeof(p)是指针大小,无法得知数组长度
聚合类型(如 struct)用列表初始化要注意顺序和可访问性
如果自己定义了一个类似数组的结构体,比如 struct Vec3 { float x,y,z; };,它属于聚合类型(aggregate),可以直接用 {} 初始化:
-
Vec3 v = {1.0f, 2.0f, 3.0f};→ 合法,按成员声明顺序赋值 -
Vec3 v{1.0f, 2.0f, 3.0f};→ 同样合法,且更“现代”(避免隐式类型转换) - 若成员含私有字段或用户定义构造函数,则不再是聚合类型,
{}初始化会失败 - 窄化仍被禁止:
Vec3 v = {1, 2, 3.5};→ 若z是float,3.5是double,可能触发窄化警告/错误(取决于编译器设置)
真正容易被忽略的是:列表初始化对聚合类型的“顺序依赖”和“不可跳过字段”——你不能写 {.x=1, .z=3}(那是 C99 designated initializer,C++20 才部分支持,且不适用于普通聚合)。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











