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 std::memory_order распространяется внутрь и наружу функции, что позволяет компилятору пропускать ненужные инструкции барьеров памяти.

Содержание

Синтаксис

[ [ carries_dependency ] ]

Объяснение

Этот атрибут может появляться в двух ситуациях:

1) это может применяться к объявлениям параметров функции или лямбда-выражений, в этом случае это указывает, что инициализация параметра переносит зависимость в преобразование lvalue-to-rvalue этого объекта.
2) Это может применяться к объявлению функции в целом, в этом случае это указывает, что возвращаемое значение несет зависимость от вычисления выражения вызова функции.

Этот атрибут должен присутствовать при первом объявлении функции или одного из ее параметров в любой единице трансляции. Если он не используется при первом объявлении функции или одного из ее параметров в другой единице трансляции, программа является некорректной; диагностика не требуется.

Пример

Адаптировано практически без изменений из Stack Overflow .

#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 является непрозрачным (предполагая, что она не встраивается),
        // поэтому компилятор должен установить барьер, чтобы гарантировать,
        // что чтение *p в функции print возвращает корректное значение.
        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 Атрибут переноса зависимостей [dcl.attr.depend]
  • Стандарт C++11 (ISO/IEC 14882:2011):
  • 7.6.4 Атрибут переноса зависимостей [dcl.attr.depend]

Смотрите также

(C++11) (устарело в C++26)
удаляет указанный объект из дерева зависимостей std::memory_order_consume
(шаблон функции)