Атрибуты в C++

Стандарт C++ определяет общий набор атрибутов. Он также позволяет поставщикам компилятора определять собственные атрибуты в пространстве имен для конкретного поставщика. Однако компиляторы должны распознавать атрибуты, определенные в стандарте.

В некоторых случаях стандартные атрибуты перекрываются с параметрами, определенными __declspec компилятором. В Microsoft C++можно использовать [[deprecated]] атрибут вместо использования __declspec(deprecated). Атрибут [[deprecated]] распознается любым соответствующим компилятором. Для всех других __declspec параметров, таких как dllimport и dllexport, до сих пор нет эквивалента атрибута, поэтому необходимо продолжать использовать __declspec синтаксис. Атрибуты не влияют на систему типов, и они не изменяют смысл программы. Компиляторы игнорируют значения атрибутов, которые они не распознают.

Visual Studio 2017 версии 15.3 и более поздних версий (доступно с /std:c++17 помощью и более поздних версий): в область списка атрибутов можно указать пространство имен для всех имен с одним using вводным элементом:

void g() {
    [[using rpr: kernel, target(cpu,gpu)]] // equivalent to [[ rpr::kernel, rpr::target(cpu,gpu) ]]
    do task();
}

Стандартные атрибуты C++

В C++11 атрибуты предоставляют стандартизированный способ аннотации конструкций C++ (включая, но не ограничивается классами, функциями, переменными и блоками) дополнительными сведениями. Атрибуты могут быть или не зависят от поставщика. Компилятор может использовать эти сведения для создания информационных сообщений или применения специальной логики при компиляции кода атрибутов. Компилятор игнорирует какие-либо атрибуты, которые он не распознает, что означает, что вы не можете определить собственные настраиваемые атрибуты с помощью этого синтаксиса. Атрибуты заключены в двойные квадратные скобки:

[[deprecated]]
void Foo(int);

Атрибуты представляют стандартизированную альтернативу расширениям для конкретных поставщиков, таким как #pragma директивы, __declspec() (Visual C++) или __attribute__ (GNU). Однако вам по-прежнему потребуется использовать конструкции, относящиеся к поставщику, для большинства целей. В настоящее время стандарт указывает следующие атрибуты, которые должен распознать соответствующий компилятор.

[[carries_dependency]]

Атрибут [[carries_dependency]] указывает, что функция распространяет порядок зависимостей данных для синхронизации потоков. Атрибут может применяться к одному или нескольким параметрам, чтобы указать, что переданный аргумент несет зависимость в теле функции. Атрибут может применяться к самой функции, чтобы указать, что возвращаемое значение несет зависимость из функции. Компилятор может использовать эти сведения для создания более эффективного кода.

[[deprecated]]

Visual Studio 2015 и более поздних версий:[[deprecated]] атрибут указывает, что функция не предназначена для использования. Кроме того, он может не существовать в будущих версиях интерфейса библиотеки. Атрибут [[deprecated]] может применяться к объявлению класса, имени типа, переменной, нестатическому элементу данных, функции, пространству имен, перечислению, перечислителю или специализации шаблона. Компилятор может использовать этот атрибут для создания информационного сообщения при попытке клиентского кода вызвать функцию. Когда компилятор Microsoft C++ обнаруживает использование [[deprecated]] элемента, он вызывает предупреждение компилятора C4996.

[[fallthrough]]

Visual Studio 2017 и более поздних версий: (доступно с и более поздними версиями /std:c++17 .) Атрибут [[fallthrough]] может использоваться в контексте инструкций switch в качестве указания компилятору (или любому пользователю, читающему код), которое предполагается в поведении. Компилятор Microsoft C++ в настоящее время не предупреждает о поведении резервного руководства, поэтому этот атрибут не влияет на поведение компилятора.

[[likely]]

Visual Studio 2019 версии 16.6 и более поздних версий: (доступно с и более поздними версиями /std:c++20 ). Атрибут [[likely]] указывает указание компилятору, что путь кода для метки или инструкции атрибута, скорее всего, будет выполняться, чем альтернативные. В компиляторе Майкрософт атрибут помечает как "горячий код", [[likely]] который увеличивает внутреннюю оценку оптимизации. Оценка увеличивается больше при оптимизации скорости, а не столько при оптимизации размера. Чистая оценка влияет на вероятность встраивание, отмену циклов и векторизацию оптимизаций. Эффект и [[likely]][[unlikely]] аналогичен оптимизации на основе профилей, но ограничен область текущей единице перевода. Оптимизация переупорядочения блоков еще не реализована для этого атрибута.

[[maybe_unused]]

Visual Studio 2017 версии 15.3 и более поздних версий: (доступно с /std:c++17 и более поздними версиями.) Атрибут [[maybe_unused]] указывает, что переменная, функция, класс, typedef, нестатический член данных, перечисление или специализация шаблона могут быть намеренно неиспользуемы. Компилятор не предупреждает, когда сущность, помеченная [[maybe_unused]] как не используется. Сущность, объявленная без атрибута, может быть переобъявлена атрибутом и наоборот. Сущность считается помеченной после первого объявления, которое помечено[[maybe_unused]], анализируется и для остальной части текущей единицы перевода.

[[nodiscard]]

Visual Studio 2017 версии 15.3 и более поздних версий: (доступно с /std:c++17 и более поздними версиями.) Указывает, что возвращаемое значение функции не предназначено для отключения карта. Вызывает предупреждение C4834, как показано в следующем примере:

[[nodiscard]]
int foo(int i) { return i * i; }

int main()
{
    foo(42); //warning C4834: discarding return value of function with 'nodiscard' attribute
    return 0;
}

[[noreturn]]

Атрибут [[noreturn]] указывает, что функция никогда не возвращается; другими словами, она всегда выдает исключение или выход. Компилятор может настроить правила компиляции для [[noreturn]] сущностей.

[[unlikely]]

Visual Studio 2019 версии 16.6 и более поздних версий: (доступно с и более поздними версиями /std:c++20 ). Атрибут [[unlikely]] указывает указание компилятору, что путь кода для метки или инструкции атрибута меньше шансов выполнить, чем альтернативные. В компиляторе Майкрософт атрибут помечает как "холодный код", [[unlikely]] который уменьшает внутреннюю оценку оптимизации. Оценка уменьшается больше при оптимизации размера, а не столько при оптимизации скорости. Чистая оценка влияет на вероятность встраивание, отмену циклов и векторизацию оптимизаций. Оптимизация переупорядочения блоков еще не реализована для этого атрибута.

Атрибуты, относящиеся к Корпорации Майкрософт

[[gsl::suppress(rules)]]

Атрибут, определенный [[gsl::suppress(rules)]] корпорацией Майкрософт, используется для подавления предупреждений от проверка еров, которые применяют правила библиотеки поддержки рекомендаций (GSL) в коде. Например, рассмотрим этот фрагмент кода:

int main()
{
    int arr[10]; // GSL warning C26494 will be fired
    int* p = arr; // GSL warning C26485 will be fired
    [[gsl::suppress(bounds.1)]] // This attribute suppresses Bounds rule #1
    {
        int* q = p + 1; // GSL warning C26481 suppressed
        p = q--; // GSL warning C26481 suppressed
    }
}

В примере возникают следующие предупреждения:

  • C26494 (правило типа 5: всегда инициализировать объект.)

  • C26485 (правило границ 3: нет массива для распада указателя.)

  • C26481 (правило границ 1. Не используйте арифметическую арифметику указателя. Вместо этого используйте диапазон.)

Первые два предупреждения возникают при компиляции этого кода с помощью средства анализа кода CppCoreCheck, установленного и активированного. Но третье предупреждение не срабатывает из-за атрибута. Вы можете отключить весь профиль границ, записав [[gsl::suppress(bounds)]] без включения определенного номера правила. Основные рекомендации по C++ предназначены для создания более эффективного и безопасного кода. Атрибут подавления упрощает отключение предупреждений, если они не нужны.

[[msvc::flatten]]

Атрибут [[msvc::flatten]] , определенный корпорацией Майкрософт, очень похож [[msvc::forceinline_calls]]на и может использоваться в одних и том же местах. Разница заключается в том, что [[msvc::flatten]][[msvc::forceinline_calls]] все вызовы в область применяются к рекурсивно, пока не останутся вызовы. Это может иметь последствия для результирующего роста размера кода функции или пропускной способности компилятора, который необходимо управлять вручную.

[[msvc::forceinline]]

При размещении перед объявлением функции атрибут [[msvc::forceinline]] , определенный корпорацией Майкрософт, имеет то же значение, что __forceinlineи .

[[msvc::forceinline_calls]]

Атрибут [[msvc::forceinline_calls]] , определенный корпорацией Майкрософт, можно поместить в инструкцию или блок или перед ней. Это приводит к тому, что встроенная эвристика пытается выполнить [[msvc::forceinline]] все вызовы в этом операторе или блоке:

void f() {
    [[msvc::forceinline_calls]]
    {
        foo();
        bar();
    }
    ...
    [[msvc::forceinline_calls]]
    bar();
    
    foo();
}

Первый вызов , и оба вызова foobar, рассматриваются как если бы они были объявлены__forceinline. Второй вызов foo не рассматривается как __forceinline.

[[msvc::intrinsic]]

Атрибут [[msvc::intrinsic]] имеет три ограничения для функции, к которую она применяется:

  • Функция не может быть рекурсивной; его текст должен иметь только оператор return с static_cast типом параметра до возвращаемого типа.
  • Функция может принимать только один параметр.
  • /permissive- Требуется параметр компилятора. (Параметры и более поздние /std:c++20 варианты подразумевают /permissive- по умолчанию.)

Атрибут, определенный [[msvc::intrinsic]] корпорацией Майкрософт, сообщает компилятору, чтобы встраивать метафункционацию, которая выступает в качестве именованного приведения из типа параметра в возвращаемый тип. Когда атрибут присутствует в определении функции, компилятор заменяет все вызовы этой функции простым приведением. Этот [[msvc::intrinsic]] атрибут доступен в Visual Studio 2022 версии 17.5 предварительной версии 2 и более поздних версий. Этот атрибут применяется только к определенной функции, следующей за ней.

Пример

В этом примере кода атрибут, примененный к my_move функции, [[msvc::intrinsic]] заменяет вызовы функции встроенным статическим приведением в тексте:

template <typename T>
[[msvc::intrinsic]] T&& my_move(T&& t) { return static_cast<T&&>(t); }

void f() {
    int i = 0;
    i = my_move(i);
}

[[msvc::noinline]]

При размещении перед объявлением функции атрибут [[msvc::noinline]] , определенный корпорацией Майкрософт, имеет то же значение, что declspec(noinline)и .

[[msvc::noinline_calls]]

Атрибут, определенный корпорацией [[msvc::noinline_calls]] Майкрософт, имеет то же использование, что [[msvc::forceinline_calls]]и атрибут. Его можно поместить перед любым оператором или блоком. Вместо принудительной встраивание всех вызовов в этом блоке, он имеет эффект отключения встраивание для область он применяется.

[[msvc::no_tls_guard]]

Атрибут, определенный [[msvc::no_tls_guard]] корпорацией Майкрософт, отключает проверка для инициализации при первом доступе к локальным переменным потока в БИБЛИОТЕКАх DLL. Проверка включены по умолчанию в коде, встроенном с помощью Visual Studio 2019 версии 16.5 и более поздних версий. Этот атрибут применяется только к определенной переменной, следующей за ней. Чтобы отключить проверка глобально, используйте параметр компилятора/Zc:tlsGuards-.