Namespaces
Variants

C++ attribute: carries_dependency (since C++11) (removed in C++26)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous
Attributes
(C++23)
carries_dependency
(C++11) (until C++26)
(C++14)
(C++20)
(C++17)
(C++11)
(C++20)

release-consumeにおける依存チェーンが関数内外に伝播することを示し、これによりコンパイラが不要なメモリフェンス命令を省略できることを可能にします。

目次

構文

[ [ carries_dependency ] ]

説明

この属性は2つの状況で現れる可能性があります:

1) これは関数またはラムダ式のパラメータ宣言に適用される場合があり、その場合、パラメータの初期化がそのオブジェクトの左辺値から右辺値への変換に依存性を持ち込むことを示します。
2) これは関数宣言全体に適用される場合があり、その場合、戻り値が関数呼び出し式の評価に対して依存関係を持つことを示します。

この属性は、任意の翻訳単位における関数またはそのパラメータの最初の宣言に現れなければなりません。他の翻訳単位における関数またはそのパラメータの最初の宣言で使用されていない場合、プログラムは不適格となります。診断は不要です。

SO からほぼ変更せずに適応。

#include <atomic>
#include <iostream>
void print(int* val)
{
    std::cout << *val << std::endl;
}
void print2(int* val [[carries_dependency]])
{
    std::cout << *val << std::endl;
}
int main()
{
    int x{42};
    std::atomic<int*> p = &x;
    int* local = p.load(std::memory_order_consume);
    if (local)
    {
        // 依存関係が明示的であるため、コンパイラはlocalが逆参照されることを認識し、
        // (一部のアーキテクチャでは)フェンスを回避するために依存チェーンが
        // 維持されることを保証しなければならない
        std::cout << *local << std::endl;
    }
    if (local)
    {
        // printの定義は不透明である(インライン化されていないと仮定)、
        // そのためコンパイラはprint内で*pを読み取る際に正しい値が
        // 返されることを保証するためにフェンスを発行しなければならない
        print(local);
    }
    if (local)
    {
        // コンパイラは、print2も不透明であるが、パラメータから逆参照された値への
        // 依存関係が命令ストリーム内で維持され、(一部のアーキテクチャでは)
        // フェンスが不要であると仮定できる。明らかに、print2の定義は実際に
        // この依存関係を維持しなければならないため、属性はprint2の生成コードにも
        // 影響を与える
        print2(local);
    }
}

出力例:

42
42
42

参考文献

  • C++23規格 (ISO/IEC 14882:2024):
  • 9.12.4 伝播依存属性 [dcl.attr.depend]
  • C++20規格 (ISO/IEC 14882:2020):
  • 9.12.3 依存関係伝播属性 [dcl.attr.depend]
  • C++17規格 (ISO/IEC 14882:2017):
  • 10.6.3 伝播依存属性 [dcl.attr.depend]
  • C++14 標準 (ISO/IEC 14882:2014):
  • 7.6.4 Carries dependency属性 [dcl.attr.depend]
  • C++11規格 (ISO/IEC 14882:2011):
  • 7.6.4 依存関係伝播属性 [dcl.attr.depend]

関連項目

(C++11) (C++26で非推奨)
指定されたオブジェクトを std::memory_order_consume 依存ツリーから削除する
(関数テンプレート)