std::atomic的平凡默认构造函数是否应遵循默认成员初始化器?
关于
std::atomic<stru>成员初始化的问题分析 咱们先把问题里的代码贴出来方便讨论:
#include <atomic> #include <iostream> struct stru { int a{}; int b{}; }; int main() { std::atomic<stru> as; auto s = as.load(); std::cout << s.a << ' ' << s.b << std::endl; }
先明确几个关键前提
- 你说的没错,C++14及以后,带默认成员初始化器的结构体
stru依然属于聚合类型。 std::atomic<stru>的默认构造函数是平凡默认构造函数——简单说就是这个构造函数啥也不做,不会主动初始化内部的stru实例。
标准到底怎么规定的?
根据C++标准的规则:
- 对于静态存储期的对象(比如定义在
main函数外面的全局变量),会先执行零初始化,再调用默认构造函数。因为std::atomic的默认构造是平凡的,啥也不做,所以最终as内部的stru成员会被零初始化,a和b都是0。 - 但对于自动存储期的对象(比如代码里
main里的as),平凡默认构造函数不会执行任何初始化操作——对象的内存就是未初始化的垃圾值,自然load()出来的a和b也不会是0。
这里要注意:stru的默认成员初始化器只有在聚合初始化的时候才会生效,而平凡默认构造函数不会触发聚合初始化。也就是说,std::atomic<stru> as;这种写法,不会调用stru的任何初始化逻辑,只是分配了一块内存而已。
为什么Clang 6.0.0没初始化?
Clang 6.0.0的行为是完全符合标准的。因为代码里的as是自动存储期的变量,用平凡默认构造创建,内存未初始化,所以输出的是随机垃圾值。
怎么让成员初始化为0?
如果想让a和b变成0,有两种方式:
- 把
as改成静态存储期,比如移到main外面定义:std::atomic<stru> as;(全局变量)。 - 用聚合初始化的方式显式初始化
as:std::atomic<stru> as{};——这会触发内部stru的聚合初始化,从而让默认成员初始化器生效,把a和b设为0。
内容的提问来源于stack exchange,提问作者Lingxi
相关产品推荐
相关产品推荐

