返回文章列表

文章

C++中”=初始化变量“和”{}初始化变量“的区别

目录
  1. 在 C++11 以后,引入了“统一初始化”(uniform initialization),也就是用一对花括号 { … } 来初始化所有类型。下面分几点来对比这两种写法的异同:
  2. 1. 语法与分类
  3. char mychar = 'a'; int myint = 123; double mydouble = 456.7; - 使用 `=` 号,是最传统的初始化方式。 - 本质上,编译器会尝试将右侧的值“转换”成目标类型,然后拷贝/赋值。 2. **列表初始化(list initialization)/直接列表初始化(direct list initialization)** c++ char mychar { 'a' }; int myint { 123 }; double mydouble{ 456.78 }; ``` - 用 {} 包裹,即可用于内置类型、类类型、聚合类型、STD 容器等。 - 有时也称为“花括号初始化”或“统一初始化”。
  4. 2. 最主要的区别:禁止窄化转换(narrowing conversions)
  5. 3. 对构造函数和 initializer_list 的影响
  6. 4. 避免 “最令人讨厌的解析”(Most Vexing Parse)
  7. 使用花括号就能彻底避免这种二义性。
  8. 5. 性能和生成代码
  9. 6. 总结

在 C++11 以后,引入了“统一初始化”(uniform initialization),也就是用一对花括号 { … } 来初始化所有类型。下面分几点来对比这两种写法的异同:#

1. 语法与分类#

  1. 拷贝初始化(copy initialization)

char mychar = 'a'; int myint = 123; double mydouble = 456.7; - 使用 `=` 号,是最传统的初始化方式。 - 本质上,编译器会尝试将右侧的值“转换”成目标类型,然后拷贝/赋值。 2. **列表初始化(list initialization)/直接列表初始化(direct list initialization)** c++ char mychar { 'a' }; int myint { 123 }; double mydouble{ 456.78 }; ``` - 用 {} 包裹,即可用于内置类型、类类型、聚合类型、STD 容器等。 - 有时也称为“花括号初始化”或“统一初始化”。#

2. 最主要的区别:禁止窄化转换(narrowing conversions)#

  • 拷贝初始化 会进行隐式转换,允许从一个类型转换到另一个类型,甚至发生精度丢失或溢出。

double d = 3.14; int i = d; // 隐式窄化:i == 3,编译器通常只给 Warning(或无提示)

```
  • 列表初始化 禁止任何窄化转换,编译期报错:

double d = 3.14; int i{ d }; // error: narrowing conversion of 'd' from 'double' to 'int'

```
这条规则让初始化更安全,能在编译期捕获精度丢失或溢出问题。

3. 对构造函数和 initializer_list 的影响#

对于自定义类型,列表初始化还会影响重载解析:

struct A {
    A(int);               // (1)
    A(std::initializer_list<int>);  // (2)
};

A a1{ 1 };   // 调用 (2) 还是 (1) ?
  • 如果存在接受 std::initializer_list 的构造,列表初始化优先匹配 initializer_list 构造函数 (2)。
  • A a2(1);(圆括号)则直接匹配 (1)。

4. 避免 “最令人讨厌的解析”(Most Vexing Parse)#

老式圆括号或等号初始化,有时会被编译器误解析为函数声明。

std::vector<int> v();   // “声明”了一个返回 vector<int> 的函数 v!
std::vector<int> v{};   // 明确是创建一个空 vector<int> 变量

使用花括号就能彻底避免这种二义性。#

5. 性能和生成代码#

  • 对于内置类型,二者性能、生成的机器码基本相同。
  • 对于类类型,拷贝初始化可能多一次“临时对象 + 拷贝/移动”,而列表/直接初始化通常更直接。但现代编译器也会做优化(如返回值优化、拷贝消除)。

6. 总结#

特性`=` 拷贝初始化`{}` 列表/直接初始化
**允许窄化转换**是(隐式转换)否(编译期报错)
**优先匹配 ****`initializer_list`**
**避免 Most Vexing Parse**有二义性风险无二义性
**适用范围**内置类型、类类型、聚合类型统一,所有类型

建议:在现代 C++ 中,如果不需要接口兼容旧代码,优先使用 {} 列表初始化,以获得更严格、更安全的类型检查和更一致的语义。