最終更新日時: 2025年10月10日 13時00分13秒 (JST)
Akira Takahashi が更新

履歴 編集

class template
<atomic>

# std::atomic_ref(C++20)

    namespace std {
      template<class T> struct atomic_ref;          // (1) C++20

      template<> struct atomic_ref<integral>;       // (2) C++20
      template<> struct atomic_ref<floating-point>; // (3) C++20
      template<class T> struct atomic_ref<T*>;      // (4) C++20
    }

## 概要

`atomic_ref`クラステンプレートは、コンストラクタで受け取った`T`型変数への参照に対してアトミック操作を適用する型である。非アトミックなオブジェクトに対して、値コピーによる`std::atomic`型変換の必要なく、アトミック操作を適用する。

オブジェクトが、多くの場面で非アトミックに使用され、競合回避のためにアトミックに振る舞う必要があるのが一部の場面である場合、オブジェクトを強制的にアトミックオブジェクトに変換してしまうことは、パフォーマンス低下につながる。`atomic_ref`クラスを使用することで、そのような状況に対応し、一部の状況でのみオブジェクトをアトミックに振る舞わせることができる。

同じオブジェクトを参照する異なる`atomic_ref`オブジェクトを介して行われるアトミック操作は、共通の参照するオブジェクトに対してアトミックに行われる。つまり、局所的に`atomic_ref`オブジェクトに変換してアトミック操作を適用してもよい。

オブジェクトを参照してアトミック操作をするための制約として、アーキテクチャ固有のアライメント制約を満たすことが要求される。コンストラクタと代入演算子でオブジェクトを参照する際、メンバ定数としてのアライメント値`required_alignment`の位置にオブジェクトが配置されていること。

`atomic_ref`クラステンプレートは型`T`の値をコピーではなく参照で保持するため、`atomic_ref`オブジェクトより先に参照先の変数の寿命が尽きてはならない。

- (1) : プライマリテンプレート。宣言のみ
- (2) : 整数型に対する特殊化 (`bool`以外)
- (3) : 浮動小数点数型に対する特殊化
  - (C++23) : 拡張浮動小数点数型を含む
- (4) : 任意の型のポインタに対する特殊化

C++26から、これらの特殊化はCV修飾された型に対しても行われるようになった。

## テンプレートパラメータ制約

- 型`T`は`is_trivially_copyable_v<T> == true`であること
- C++26: `is_always_lock_free`が`false`かつ`is_volatile_v`が`true`である場合、プログラムは不適格となる

## メンバ関数

### 共通メンバ関数

名前 | 説明 | 対応バージョン
--- | --- | ---
`(constructor)` | コンストラクタ | C++20
`~atomic_ref() = default` | デストラクタ | C++20
`operator=` | 代入 | C++20
`is_lock_free` | オブジェクトがロックフリーに振る舞えるかを判定する | C++20
`store` | 値を書き込む | C++20
`load` | 値を読み込む | C++20
`operator T` | 型`T`への変換演算子 | C++20 (C++26で`value_type`に変更)
`operator value_type` | 型`value_type`への変換演算子 | C++26
`exchange` | 値を入れ替える | C++20
`compare_exchange_weak` | 弱い比較で値を入れ替える | C++20
`compare_exchange_strong` | 強い比較で値を入れ替える | C++20
`wait` | 起床されるまで待機する | C++20
`notify_one` | 待機しているスレッドをひとつ起床させる | C++20
`notify_all` | 待機している全てのスレッドを起床させる | C++20
`address` | 参照しているオブジェクトのアドレスを取得する | C++26

### 共通メンバ型

名前 | 説明 | 対応バージョン
--- | --- | ---
`value_type` | 要素型となるテンプレートパラメータの型。 C++20: `T` C++26: `remove_cv_t<T>` | C++20

### 共通メンバ定数

名前 | 説明 | 対応バージョン
--- | --- | ---
`static constexpr bool is_always_lock_free` | 型`T`に対するアトミック操作が常にロックフリー (非ミューテックス) で動作する場合は`true`、そうでなければ`false` | C++20
`static constexpr size_t required_alignment` | 参照するオブジェクトに要求されるアライメント。少なくとも`alignof(T)` | C++20

`is_always_lock_free == true`の場合、このクラスのオブジェクトをシグナルハンドラー内で使用できる。

`required_alignment`について、ハードウェアは参照するオブジェクトに対して、型`T`のほかのオブジェクトよりも厳密なアライメントを持つことを要求できる。また、`atomic_ref`がロックフリーかどうかは、参照するオブジェクトのアライメントに依存する。たとえば`std::complex<double>`のロックフリー操作は`2 * alignof(double)`にアライメントされる場合にのみサポートされる。

### atomic_ref<integral>専用メンバ関数

整数型に対する特殊化。

名前 | 説明 | 対応バージョン
--- | --- | ---
`fetch_add` | 加算 | C++20
`fetch_sub` | 減算 | C++20
`fetch_and` | AND演算 | C++20
`fetch_or` | OR演算 | C++20
`fetch_xor` | XOR演算 | C++20
`fetch_max` | 最大値を設定・取得 | C++26
`fetch_min` | 最小値を設定・取得 | C++26
`store_add` | 値を読み込まずに加算 | C++26
`store_sub` | 値を読み込まずに減算 | C++26
`store_and` | 値を読み込まずにAND演算 | C++26
`store_or` | 値を読み込まずにOR演算 | C++26
`store_xor` | 値を読み込まずにXOR演算 | C++26
`store_max` | 値を読み込まずに最大値を設定 | C++26
`store_min` | 値を読み込まずに最小値を設定 | C++26
`operator++` | インクリメント | C++20
`operator--` | デクリメント | C++20
`operator+=` | 加算 | C++20
`operator-=` | 減算 | C++20
`operator&=` | AND演算 | C++20
`operator|=` | OR演算 | C++20
`operator^=` | XOR演算 | C++20

### atomic_ref<integral>専用メンバ型

名前 | 説明 | 対応バージョン
--- | --- | ---
`difference_type` | 2つの値の差を表す整数型`value_type` | C++20

### atomic_ref<floating-point>専用メンバ関数

浮動小数点数型に対する特殊化。

名前 | 説明 | 対応バージョン
--- | --- | ---
`fetch_add` | 加算 | C++20
`fetch_sub` | 減算 | C++20
`fetch_max` | 最大値を設定・取得 | C++26
`fetch_min` | 最小値を設定・取得 | C++26
`fetch_fmaximum` | 最大値を設定・取得 (`-0.0`と`+0.0`では`+0.0`、NaNと値ではNaNを返す) | C++26
`fetch_fminimum` | 最小値を設定・取得 (`-0.0`と`+0.0`では`-0.0`、NaNと値ではNaNを返す) | C++26
`fetch_fmaximum_num` | 最大値を設定・取得 (`-0.0`と`+0.0`では`+0.0`、NaNと値では数値を返す) | C++26
`fetch_fminimum_num` | 最小値を設定・取得 (`-0.0`と`+0.0`では`-0.0`、NaNと値では数値を返す) | C++26
`store_add` | 値を読み込まずに加算 | C++26
`store_sub` | 値を読み込まずに減算 | C++26
`store_and` | 値を読み込まずにAND演算 | C++26
`store_or` | 値を読み込まずにOR演算 | C++26
`store_xor` | 値を読み込まずにXOR演算 | C++26
`store_max` | 値を読み込まずに最大値を設定 | C++26
`store_min` | 値を読み込まずに最小値を設定 | C++26
`store_fmaximum` | 値を読み込まずに最大値を設定 (`-0.0`と`+0.0`では`+0.0`、NaNと値ではNaNを返す) | C++26
`store_fminimum` | 値を読み込まずに最小値を設定 (`-0.0`と`+0.0`では`-0.0`、NaNと値ではNaNを返す) | C++26
`store_fmaximum_num` | 値を読み込まずに最大値を設定 (`-0.0`と`+0.0`では`+0.0`、NaNと値では数値を返す) | C++26
`store_fminimum_num` | 値を読み込まずに最小値を設定 (`-0.0`と`+0.0`では`-0.0`、NaNと値では数値を返す) | C++26
`operator+=` | 加算 | C++20
`operator-=` | 減算 | C++20

### atomic_ref<floating-point>専用メンバ型

名前 | 説明 | 対応バージョン
--- | --- | ---
`difference_type` | 2つの値の差を表す整数型`value_type` | C++20

### atomic_ref<T*>専用メンバ関数

ポインタ型に対する特殊化。

名前 | 説明 | 対応バージョン
--- | --- | ---
`fetch_add` | 加算 | C++20
`fetch_sub` | 減算 | C++20
`fetch_max` | 最大値を設定・取得 | C++26
`fetch_min` | 最小値を設定・取得 | C++26
`store_add` | 値を読み込まずに加算 | C++26
`store_sub` | 値を読み込まずに減算 | C++26
`store_max` | 値を読み込まずに最大値を設定 | C++26
`store_min` | 値を読み込まずに最小値を設定 | C++26
`operator++` | インクリメント | C++20
`operator--` | デクリメント | C++20
`operator+=` | 加算 | C++20
`operator-=` | 減算 | C++20

### atomic_ref<T*>専用メンバ型

名前 | 説明 | 対応バージョン
--- | --- | ---
`difference_type` | 2つの値の差を表す整数型`ptrdiff_t` | C++20

### 例

    #include <iostream>
    #include <atomic>
    #include <thread>

    struct Info {
      int value = 0;
    };

    int main()
    {
      Info info;

      std::thread consumer_thread {[&info] {
        std::atomic_ref<int> x{info.value};
        while (true) {
           if (int value = x.exchange(0); value != 0) {
             std::cout << value << std::endl;
             break;
           }
        }
      }};

      std::atomic_ref{info.value}.store(3); // クラステンプレートのテンプレート引数推論も使用できる (<int>省略)
      consumer_thread.join();
    }

### 出力

    3

## バージョン

### 言語

- C++20

### 処理系

- Clang: 9.0 ❌
- GCC: 10.1 ✅
- Visual C++: ??

## 関連項目

- `std::atomic`

### 参照

- P0019R8 Atomic Ref
- P1467R9 Extended floating-point types and standard names
  - C++23で拡張浮動小数点数型もテンプレート引数として指定することが許可された
- P3323R1 cv-qualified types in `atomic` and `atomic_ref`
  - C++26でCV修飾されたテンプレート引数を受け取れるようになった