std::atomic_ref可将普通对象转为原子操作引用,适用于无法修改原类型的场景。它不拥有内存,仅提供原子视图,要求被引用对象类型可平凡复制、正确对齐且生命周期覆盖atomic_ref使用期。示例中两个线程通过atomic_ref对int进行原子递增,最终结果为2000。支持load、store、fetch_add等操作,整型和指针还支持位运算,浮点型自c++20起支持算术操作。可通过is_always_lock_free判断是否无锁,运行时也可调用is_lock_free查询。为确保对齐,可使用alignas指定。该工具强大但限制多,需谨慎使用以保证安全。

在C++20中,std::atomic_ref 提供了一种将已有普通对象包装成原子操作引用的方式,允许对非原子变量进行原子访问,而无需将其声明为 atomic 类型。这个特性特别适用于需要对已有数据结构添加原子操作能力,但又不能修改其定义的场景。
基本用法与要求
std::atomic_ref 不持有对象内存,它只是一个对已有对象的“原子视图”。创建 atomic_ref 时需传入一个对象的引用。
使用限制较多,必须满足以下条件:
- 被引用的对象类型必须是可平凡复制(trivially copyable)
- 对象的地址必须正确对齐(alignment)以支持原子操作
- 对象在整个 atomic_ref 生命周期内不能被销毁
- atomic_ref 实例本身不能被拷贝或移动(不可复制)
注意:如果对象未满足对齐或生命周期要求,行为未定义。
简单示例
下面是一个使用 std::atomic_ref 对 int 变量进行原子加的操作:
立即学习“C++免费学习笔记(深入)”;
#include <iostream> #include <atomic> #include <thread> int main() { int value = 0; std::atomic_ref atomic_value{value}; // 绑定到 value auto worker = [&]() { for (int i = 0; i < 1000; ++i) { atomic_value.fetch_add(1, std::memory_order_relaxed); } }; std::thread t1(worker); std::thread t2(worker); t1.join(); t2.join(); std::cout << "Final value: " << value << "n"; // 应输出 2000 }
这里,尽管 value 是普通 int,通过 atomic_ref 可以安全地在多线程中进行原子递增。
支持的操作
atomic_ref 支持大多数原子操作,具体取决于所引用类型的性质:
- load() / store()
- fetch_add() / fetch_sub()
- exchange() / compare_exchange_weak() / compare_exchange_strong()
- fetch_and() / fetch_or() / fetch_xor() (仅整数和指针类型)
浮点类型还支持 fetch_add 和 fetch_sub(C++20起)。
对齐与兼容性检查
可通过 is_always_lock_free 静态成员判断该类型是否在当前平台支持无锁原子操作:
if (std::atomic_ref<int>::is_always_lock_free) { std::cout << "int atomic_ref is lock-freen"; }
也可在运行时使用 .is_lock_free() 查询。
若不确定对象是否对齐,可使用 alignas 确保:
alignas(std::atomic_ref<int>) int aligned_value = 0;
基本上就这些。std::atomic_ref 是个强大但需谨慎使用的工具,适合底层并发编程或封装遗留代码的原子访问,只要注意对齐、生命周期和类型限制,就能安全发挥其作用。


