You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

显式调用平凡默认构造为何产生额外赋值?NoInit构造优化疑问

咱们先把核心问题拆解清楚——你遇到的差异本质上是C++里**值初始化(Value Initialization)和默认初始化(Default Initialization)**的规则区别,再加上类成员in-class初始化器的行为影响,一步步来解释:

1. 为什么A(DefaultInit)和A(NoInit)表现不同?

先看struct A的两个构造函数:

A(DefaultInit) : a(), b(), c() {} // 生成赋值0的汇编
A(NoInit) {} // 无任何汇编代码

当你在成员初始化列表里写a()、c()这种形式时,触发的是值初始化,而非默认初始化:

  • 对于std::atomic<long>:它的默认构造函数是平凡的(啥也不做),但值初始化规则要求,对拥有平凡默认构造函数的类类型,会先零初始化对象,再调用默认构造函数(而后者不执行任何操作)。最终结果就是这些atomic成员被强制设为0,所以汇编里会出现赋值指令。
  • 对于int c:标量类型的值初始化就是零初始化,因此也会生成赋值0的代码。

而A(NoInit) {}没有显式初始化任何成员,触发的是默认初始化:

  • std::atomic<long>的默认初始化就是调用它的平凡构造函数,完全不做任何操作,自然无汇编代码。
  • int c的默认初始化是不执行任何初始化,所以也不会生成相关汇编。

2. 为什么struct B的B(NoInit) : a(), b(), c()会生成赋值0的代码?

struct B的成员带有in-class初始化器(a{1}、b{2}、c{3}),这会改变构造函数的行为逻辑:

  • 如果你在构造函数的成员初始化列表里没有提到某个成员,编译器会自动用in-class初始化器来初始化它(比如默认构造函数B() {}就会把a设为1,b设为2,c设为3,符合你的预期)。
  • 但当你显式写a()、b()、c()时,你覆盖了in-class初始化器,同时触发了值初始化——和struct A的情况一致,atomic成员被零初始化,int也被零初始化,所以汇编里出现赋值0的指令。

3. 如何让B(NoInit)的行为和A(NoInit)完全一致?

你想要的是完全跳过所有初始化(包括in-class初始化器的执行),这时候需要用默认初始化的语法,同时覆盖in-class初始化器的默认行为。在C++11及以后,你可以用空的成员初始化器(只写成员名,不写括号或大括号)来触发默认初始化:

struct B {
    std::atomic<long> a{1};
    std::atomic<long> b{2};
    int c{3};

    B() {} // 行为符合预期,使用in-class初始化器
    B(NoInitCorrect) : a, b, c {} // 正确写法:触发默认初始化
};

这里的a, b, c就是告诉编译器:对这些成员执行默认初始化,既不使用值初始化,也不使用in-class初始化器。这样:

  • std::atomic<long>的默认初始化调用平凡构造函数,不做任何操作。
  • int c的默认初始化不执行任何初始化。
    最终生成的汇编就会和A(NoInit)完全一致,没有任何赋值指令。

需要注意的是,这种默认初始化后的成员值是未定义的(完全符合你想要的"NoInit"语义),标准允许编译器做任何处理,但实际场景中它们会保留内存里的原有垃圾值,完全满足你的需求。


内容的提问来源于stack exchange,提问作者themagicalyang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:28:39