空花括号{}对内置类型触发值初始化,结果为零初始化:int为0、double为0.0、bool为false、指针为nullptr;数组int arr[5]{}所有元素全为0;char c{}得'\0';const变量必须初始化,const int x{}合法;类对象myclass obj{}调用默认构造函数或零初始化;std::string s{}和std::vector v{}均构造空容器。

空花括号 {} 对内置类型做值初始化
写 int x{}; 或 double d{}; 会触发「值初始化」,结果是零初始化:整型为 0,浮点型为 0.0,bool 为 false,指针为 nullptr。这和 int x = 0; 效果一致,但语义更明确——你不是在赋值,而是在声明时就要求“清零”。
容易踩的坑:
-
int arr[5]{};所有元素全为0;但int arr[5];(无初始化)在局部作用域下值是未定义的 -
char c{};得到'\0',不是随机字节;而char c;在栈上可能残留垃圾值 - 对
const变量必须初始化,const int x{};合法且安全,const int x;直接编译失败
{} 初始化类对象时调用默认构造函数或值初始化
对于自定义类,MyClass obj{}; 的行为取决于类是否有用户提供的默认构造函数:
- 如果有
MyClass() = default;或显式定义的默认构造函数,就调用它 - 如果没有,默认执行「值初始化」:先零初始化内存(所有成员置零),再调用默认构造函数(若存在);若无默认构造函数,则只做零初始化(POD 类型常见)
-
std::string s{};和std::vector<int> v{};</int>都构造出空容器,等价于std::string s;(但后者在局部作用域不保证为空,而{}强制为空)
注意:MyClass obj;(无括号)在某些上下文中可能被解析为函数声明(Most Vexing Parse),而 obj{} 绝对不会。
数组、容器用 {} 初始化的边界行为
空花括号在聚合类型和标准容器中含义清晰,但细节差异大:
-
int arr[3]{};→ 全部三个元素为0 -
std::array<int> a{};</int>→ 同样全为0,且是常量表达式友好 -
std::vector<int> v{};</int>→ 构造空容器,v.size() == 0,不分配堆内存 -
std::vector<int> v{1, 2, 3};</int>→ 调用initializer_list构造函数;但v{}不走这条路径,而是匹配默认构造函数 -
std::map<int std::string> m{};</int>→ 空 map,不是未定义行为;而m;(无初始化)在局部变量中也合法,但语义不如{}明确
为什么不能写 int x{1, 2}; 却能写 std::vector<int> v{1, 2};</int>
这是花括号初始化最易混淆的一点:编译器优先尝试 initializer_list 构造,但仅当目标类型有接受 std::initializer_list 的构造函数时才成功。
内置类型如 int 没有这种构造函数,所以 int x{1, 2}; 编译报错(too many initializers);而 std::vector 有 vector(initializer_list<t>)</t>,所以 v{1, 2} 正确。
关键推论:
-
std::string s{};是值初始化(空字符串),不是initializer_list<const char></const>构造 -
std::string s{"hello"};才是调用initializer_list<char></char>构造函数(逐字符构造) - 想强制走某构造函数?加
explicit或避免花括号歧义,比如用std::string s("hello");
空花括号看似简单,但它把「零值」「空状态」「默认行为」三者绑死在语法层面——一旦你习惯写 {},就很难再容忍裸声明带来的不确定性。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











