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)

Indique que la chaîne de dépendance dans l'ordre release-consume std::memory_order se propage à l'intérieur et à l'extérieur de la fonction, ce qui permet au compilateur de sauter les instructions de barrière mémoire inutiles.

Table des matières

Syntaxe

[ [ carries_dependency ] ]

Explication

Cet attribut peut apparaître dans deux situations :

1) il peut s'appliquer aux déclarations de paramètres d'une fonction ou d'expressions lambda, auquel cas il indique que l'initialisation du paramètre introduit une dépendance dans la conversion lvalue-vers-rvalue de cet objet.
2) Il peut s'appliquer à la déclaration de fonction dans son ensemble, auquel cas il indique que la valeur de retour porte une dépendance à l'évaluation de l'expression d'appel de fonction.

Cet attribut doit apparaître sur la première déclaration d'une fonction ou de l'un de ses paramètres dans toute unité de traduction. S'il n'est pas utilisé sur la première déclaration d'une fonction ou de l'un de ses paramètres dans une autre unité de traduction, le programme est mal formé ; aucun diagnostic requis.

Exemple

Adapté presque sans modification de 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)
    {
        // The dependency is explicit, so the compiler knows that local is
        // dereferenced, and that it must ensure that the dependency chain
        // is preserved in order to avoid a fence (on some architectures).
        std::cout << *local << std::endl;
    }
    if (local)
    {
        // The definition of print is opaque (assuming it is not inlined),
        // so the compiler must issue a fence in order to ensure that
        // reading *p in print returns the correct value.
        print(local);
    }
    if (local)
    {
        // The compiler can assume that although print2 is also opaque then
        // the dependency from the parameter to the dereferenced value is
        // preserved in the instruction stream, and no fence is necessary (on
        // some architectures). Obviously, the definition of print2 must actually
        // preserve this dependency, so the attribute will also impact the
        // generated code for print2.
        print2(local);
    }
}

Sortie possible :

42
42
42

Références

  • Norme C++23 (ISO/IEC 14882:2024) :
  • 9.12.4 Attribut porte une dépendance [dcl.attr.depend]
  • Norme C++20 (ISO/CEI 14882:2020) :
  • 9.12.3 Attribut porte une dépendance [dcl.attr.depend]
  • Norme C++17 (ISO/IEC 14882:2017) :
  • 10.6.3 Attribut porte une dépendance [dcl.attr.depend]
  • Norme C++14 (ISO/CEI 14882:2014) :
  • 7.6.4 Attribut porte une dépendance [dcl.attr.depend]
  • Norme C++11 (ISO/IEC 14882:2011) :
  • 7.6.4 Attribut porte une dépendance [dcl.attr.depend]

Voir aussi

(C++11) (déprécié en C++26)
retire l'objet spécifié de l'arbre de dépendance std::memory_order_consume
(modèle de fonction)