等号初始化本质是拷贝初始化,调用拷贝/移动构造函数而非operator=;括号初始化是直接初始化但有歧义风险;大括号初始化禁止窄化转换且不依赖拷贝语义。

等号初始化(=)本质是拷贝初始化
写 Widget w = Widget{} 或 std::string s = "hello",表面上像赋值,实际不是。它调用的是拷贝构造函数(或移动构造函数),而非 operator=。编译器可能优化掉临时对象(复制省略),但语义上仍是“构造一个临时对象,再用它初始化目标”。对用户自定义类型,这意味着:如果拷贝/移动构造函数被 delete,哪怕 operator= 是可用的,= 初始化也会失败。
括号初始化(())是直接初始化,但有歧义风险
Widget w() 看起来像创建默认对象,实则是函数声明——C++ 最令人头疼的解析(most vexing parse)。这种语法在构造无参对象时完全不可靠。另外,std::vector<int> v(10, 42)</int> 这种两参数形式明确走构造函数重载,但 v(10) 和 v{10} 含义完全不同:v(10) 创建含 10 个默认值元素的 vector;v{10} 创建含单个元素 10 的 vector。
-
std::vector<int> v1(5);</int>→ 5 个int{}(即 5 个 0) -
std::vector<int> v2{5};</int>→ 1 个元素,值为 5 -
std::vector<int> v3 = {5};</int>→ 同v2,也是列表初始化
等号初始化不支持不可拷贝类型
像 std::atomic<int></int>、std::unique_ptr 这类禁用拷贝的类型,不能用 = 初始化:
std::atomic<int> a1 = 42; // ❌ 编译错误:拷贝构造函数被 delete
std::atomic<int> a2(42); // ✅ 直接初始化
std::atomic<int> a3{42}; // ✅ 列表初始化
</int></int></int>
这是因为 = 强制触发拷贝/移动语义,而括号和大括号可绕过该路径,直接调用匹配的构造函数。
窄化转换行为差异暴露隐性风险
当从高精度类型转低精度类型时,= 和 () 都允许隐式窄化(如 double → int),但 {} 会报错。不过注意:= 初始化本身不改变窄化规则——int x = 3.14; 合法,但 int x = {3.14}; 不合法。真正严格禁止窄化的,是纯大括号形式(int x{3.14};)和等号+大括号组合(int x = {3.14};)。
这个区别常被忽略:你改用 = 就可能无意中放过本该捕获的精度丢失问题,尤其在跨平台或浮点计算场景下。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











