std::atomic要求自定义结构体必须是trivially_copyable且大小不超过16字节;否则编译失败或退化为锁实现。常见违规包括显式析构函数、虚函数、非平凡成员(如std::string)及超限尺寸。

std::atomic 要求自定义结构体是 trivially copyable
不是所有 struct 都能套 std::atomic,最硬的门槛是:它必须是 trivially_copyable。编译器会检查这个约束,不满足就直接报错——不是运行时问题,而是模板实例化失败。
常见踩坑点:
- 含有非 trivial 析构函数(哪怕空实现,只要显式写了 ~MyStruct() {})就不行
- 有虚函数、虚基类、non-trivial 拷贝/移动构造或赋值函数
- 成员含 std::string、std::vector、std::shared_ptr 等非 trivial 类型
- 即使所有成员都是 POD,但加了 private: 或 protected: 也不影响 triviality,真正卡住的是语义而非访问控制
验证方式很简单:
static_assert(std::is_trivially_copyable_v<MyStruct>);
std::atomic 还要求 sizeof(T) ≤ 最大原子操作宽度(通常为 16 字节)
即使结构体是 trivially copyable,如果太大,std::atomic 可能无法提供 lock-free 实现,甚至某些平台根本禁用特化。
关键事实:
- std::atomic<t>::is_always_lock_free</t> 在 C++17+ 中是 constexpr,可编译期判断
- x86-64 上,多数编译器对 ≤16 字节的 trivially copyable 类型支持 lock-free load/store(通过 movaps / cmpxchg16b 等指令)
- 超过 16 字节(比如含 4 个 double 的 struct),std::atomic 会退化为内部加锁(mutex),性能断崖下跌,且不能用于无锁算法
- 注意:alignof(T) 也得匹配硬件要求(如 16 字节对齐),否则可能触发未定义行为或强制锁实现
实操建议:
static_assert(sizeof(MyStruct) <= 16);<br>static_assert(alignof(MyStruct) % alignof(std::max_align_t) == 0);
立即学习“C++免费学习笔记(深入)”;
std::atomic 不支持部分成员操作,只能整体读写
你不能对 struct 的某个字段做原子加法或 CAS,std::atomic 提供的 fetch_add、compare_exchange_weak 等操作,作用对象是整个 struct 的比特序列。
这意味着:
- 没有“原子地给 struct 里某个 int 成员加 1”的语法,必须读-改-写整个 struct
- 如果两个线程同时修改不同字段,仍可能发生 ABA 或丢失更新(因为 CAS 是全量比对)
- 若需字段级原子性,得把字段单独拎出来用 std::atomic,而不是包进 struct 里再套一层
- 即使 struct 只有一个 int 成员,用 std::atomic<mystruct></mystruct> 也比直接用 std::atomic<int></int> 多一层间接和对齐开销
std::atomic 的默认构造不初始化内存,容易误用
std::atomic<mystruct> x;</mystruct> 不等于 MyStruct{} 初始化,它执行的是默认初始化(即未定义值),尤其当 struct 含 padding 时,padding 位是随机的。
后果很实际:
- compare_exchange_weak 可能因 padding 位不一致而意外失败
- 不同线程看到的“相同逻辑值”可能有不同比特表示,破坏原子操作语义
- 必须显式初始化:
std::atomic<MyStruct> x{MyStruct{}}; // 值初始化,零填充 padding- 更安全的做法是用
std::atomic_init(&x, MyStruct{});(C++20 前推荐,避免静态初始化顺序问题)
别依赖编译器“帮你清零”,它不会。








