Atributy v jazyce C++

Standard jazyka C++ definuje společnou sadu atributů. Umožňuje také dodavatelům kompilátoru definovat vlastní atributy v rámci oboru názvů specifického dodavatele. Kompilátory jsou však nutné pouze k rozpoznávání atributů definovaných ve standardu.

V některých případech se standardní atributy překrývají s parametry specifickými pro __declspec kompilátor. V jazyce Microsoft C++ můžete místo použití __declspec(deprecated)použít [[deprecated]] atribut . Atribut [[deprecated]] je rozpoznán jakýmkoli odpovídajícím kompilátorem. Pro všechny ostatní __declspec parametry, například dllimport a dllexport, zatím neexistuje žádný ekvivalent atributu, takže je nutné pokračovat v používání __declspec syntaxe. Atributy nemají vliv na systém typů a nemění význam programu. Kompilátory ignorují hodnoty atributů, které nerozpoznávají.

Visual Studio 2017 verze 15.3 a novější (k dispozici pro /std:c++17 a novější): V oboru seznamu atributů můžete zadat obor názvů pro všechny názvy pomocí jediného using zastupovače:

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

Standardní atributy C++

V jazyce C++11 poskytují atributy standardizovaný způsob přidávání poznámek k konstruktorům jazyka C++ (včetně tříd, funkcí, proměnných a bloků) s dalšími informacemi. Atributy mohou nebo nemusí být specifické pro dodavatele. Kompilátor může tyto informace použít ke generování informačních zpráv nebo k použití speciální logiky při kompilaci atributového kódu. Kompilátor ignoruje všechny atributy, které nerozpozná, což znamená, že pomocí této syntaxe nemůžete definovat vlastní atributy. Atributy jsou uzavřeny dvojitými hranatými závorkami:

[[deprecated]]
void Foo(int);

Atributy představují standardizovanou alternativu k rozšířením specifickým pro dodavatele, jako #pragma jsou direktivy ( __declspec() Visual C++) nebo __attribute__ (GNU). Pro většinu účelů ale budete muset použít konstrukce specifické pro dodavatele. Standard aktuálně určuje následující atributy, které by měl rozpoznat odpovídající kompilátor.

[[carries_dependency]]

Atribut [[carries_dependency]] určuje, že funkce šíří pořadí závislostí dat pro synchronizaci vláken. Atribut lze použít na jeden nebo více parametrů, aby bylo možné určit, že předaný argument nese závislost do těla funkce. Atribut lze použít na samotnou funkci, aby bylo možné určit, že návratová hodnota provádí závislost mimo funkci. Kompilátor může tyto informace použít k vygenerování efektivnějšího kódu.

[[deprecated]]

Visual Studio 2015 a novější: Atribut [[deprecated]] určuje, že funkce není určená k použití. Nebo že nemusí existovat v budoucích verzích rozhraní knihovny. Atribut [[deprecated]] lze použít pro deklaraci třídy, typedef-name, proměnnou, nestatický datový člen, funkci, obor názvů, výčet, enumerátor nebo specializaci šablony. Kompilátor může tento atribut použít k vygenerování informační zprávy, když se klientský kód pokusí volat funkci. Když kompilátor Microsoft C++ zjistí použití [[deprecated]] položky, vyvolá upozornění kompilátoru C4996.

[[fallthrough]]

Visual Studio 2017 a novější: (K dispozici s a novějšími verzemi /std:c++17 )) Atribut [[fallthrough]] lze použít v kontextu switch příkazů jako nápovědu kompilátoru (nebo kdokoli, kdo čte kód), že je úmyslné chování při pádu. Kompilátor jazyka Microsoft C++ v současné době nevaruje při pádovém chování, takže tento atribut nemá žádný vliv na chování kompilátoru.

[[likely]]

Visual Studio 2019 verze 16.6 a novější: (k dispozici s a novějšími verzemi /std:c++20 ).) Atribut [[likely]] určuje nápovědu kompilátoru, že cesta kódu pro atributovaný popisek nebo příkaz je s větší pravděpodobností spuštěna než alternativy. V kompilátoru [[likely]] Microsoftu označuje atribut bloky jako "horký kód", což zvýší interní skóre optimalizace. Skóre se zvýší více při optimalizaci rychlosti, a ne tolik při optimalizaci velikosti. Čisté skóre ovlivňuje pravděpodobnost vkládání, zrušení registrace smyčky a vektorizace optimalizací. Účinek [[likely]] a [[unlikely]] je podobný optimalizaci s asistencí profilu, ale je omezený v rozsahu na aktuální jednotku překladu. Optimalizace změny pořadí bloků ještě není pro tento atribut implementována.

[[maybe_unused]]

Visual Studio 2017 verze 15.3 a novější: (k dispozici s a novějšími verzemi /std:c++17 ).) Atribut [[maybe_unused]] určuje, že proměnná, funkce, třída, typedef, nestatický datový člen, výčet nebo specializace šablony může být záměrně nepoužitá. Kompilátor neupozorní, když se entita označená [[maybe_unused]] nepoužívá. Entita deklarovaná bez atributu může být později předepisována atributem a naopak. Entita se považuje za označenou po první deklaraci, která je označena [[maybe_unused]] , se analyzuje a zbytek aktuální jednotky překladu.

[[nodiscard]]

Visual Studio 2017 verze 15.3 a novější: (k dispozici s a novějšími verzemi /std:c++17 ).) Určuje, že návratová hodnota funkce není určena k zahození. Vyvolá upozornění C4834, jak je znázorněno v tomto příkladu:

[[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]]

Atribut [[noreturn]] určuje, že funkce nikdy nevrací; jinými slovy vždy vyvolá výjimku nebo ukončí. Kompilátor může upravit pravidla kompilace pro [[noreturn]] entity.

[[unlikely]]

Visual Studio 2019 verze 16.6 a novější: (k dispozici s a novějšími verzemi /std:c++20 ).) Atribut [[unlikely]] určuje nápovědu kompilátoru, že cesta kódu pro atributovaný popisek nebo příkaz je méně pravděpodobné než alternativy. V kompilátoru [[unlikely]] Microsoftu označuje atribut bloky jako "studený kód", což sníží interní skóre optimalizace. Skóre se při optimalizaci velikosti sníží, a ne tolik při optimalizaci rychlosti. Čisté skóre ovlivňuje pravděpodobnost vkládání, zrušení registrace smyčky a vektorizace optimalizací. Optimalizace změny pořadí bloků ještě není pro tento atribut implementována.

Atributy specifické pro Microsoft

[[gsl::suppress(rules)]]

Atribut specifický pro [[gsl::suppress(rules)]] Microsoft se používá k potlačení upozornění z kontrolních metod, které vynucují pravidla knihovny GSL (Guidelines Support Library) v kódu. Představte si například tento fragment kódu:

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
    }
}

V příkladu se zobrazí tato upozornění:

  • C26494 (Pravidlo 5 typu: Vždy inicializovat objekt.)

  • C26485 (Hranice– pravidlo 3: Nerozkládají se žádné pole ukazatele.)

  • C26481 (Hranice 1: Nepoužívejte aritmetický ukazatel. Místo toho použijte rozsah.)

První dvě upozornění se aktivují při kompilaci tohoto kódu pomocí nainstalovaného a aktivovaného nástroje pro analýzu kódu CppCoreCheck. Třetí upozornění se ale kvůli atributu neaktivuje. Celý profil hranic můžete potlačit zápisem [[gsl::suppress(bounds)]] bez zahrnutí konkrétního čísla pravidla. Pokyny pro C++ Core Guidelines jsou navržené tak, aby vám pomohly psát lepší a bezpečnější kód. Atribut potlačení usnadňuje vypnutí upozornění, když nejsou požadované.

[[msvc::flatten]]

Atribut [[msvc::flatten]] specifický pro Microsoft je velmi podobný [[msvc::forceinline_calls]]a lze jej použít na stejných místech a stejným způsobem. Rozdíl spočívá v tom, že [[msvc::flatten]][[msvc::forceinline_calls]] všechna volání v oboru, který se použije rekurzivně, dokud nezůstane žádná volání. To může mít důsledky pro výsledný růst velikosti kódu funkce nebo propustnost kompilátoru, kterou musíte spravovat ručně.

[[msvc::forceinline]]

Při umístění před deklaraci funkce má atribut [[msvc::forceinline]] specifický pro Microsoft stejný význam jako __forceinline.

[[msvc::forceinline_calls]]

Atribut [[msvc::forceinline_calls]] specifický pro Microsoft lze umístit na příkaz nebo blok nebo před něj. Způsobí, že se vložená heuristika pokusí o [[msvc::forceinline]] všechna volání v daném příkazu nebo bloku:

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

První volání foo, a oba volání bar, jsou považovány za to, jako by byly deklarovány __forceinline. Druhé volání foo není považováno za __forceinlinevolání .

[[msvc::intrinsic]]

Atribut [[msvc::intrinsic]] má tři omezení funkce, na které se vztahuje:

  • Funkce nemůže být rekurzivní; jeho tělo musí mít pouze návratový příkaz s typem static_cast parametru do návratového typu.
  • Funkce může přijmout pouze jeden parametr.
  • Je vyžadována možnost kompilátoru /permissive- . (Ve výchozím nastavení to znamená /permissive- následující /std:c++20 možnosti.)

Atribut specifický pro [[msvc::intrinsic]] Microsoft říká kompilátoru, aby vloženého metafunkce, který funguje jako pojmenované přetypování z typu parametru na návratový typ. Pokud je atribut v definici funkce, kompilátor nahradí všechna volání této funkce jednoduchým přetypováním. Atribut [[msvc::intrinsic]] je k dispozici v sadě Visual Studio 2022 verze 17.5 Preview 2 a novějších verzích. Tento atribut se vztahuje pouze na konkrétní funkci, která ji následuje.

Příklad

V tomto ukázkovém kódu [[msvc::intrinsic]] atribut použitý na my_move funkci nahradí volání kompilátoru vloženým statickým přetypováním v těle funkce:

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]]

Při umístění před deklaraci funkce má atribut [[msvc::noinline]] specifický pro Microsoft stejný význam jako declspec(noinline).

[[msvc::noinline_calls]]

Atribut [[msvc::noinline_calls]] specifický pro Microsoft má stejné použití jako [[msvc::forceinline_calls]]. Lze jej umístit před jakýkoli příkaz nebo blok. Místo vynucení vkládání všech volání v tomto bloku má vliv na vypnutí vkládání pro obor, na který se vztahuje.

[[msvc::no_tls_guard]]

Atribut specifický pro [[msvc::no_tls_guard]] Microsoft zakáže kontroly inicializace při prvním přístupu k lokálním proměnným vlákna v knihovnách DLL. Kontroly jsou ve výchozím nastavení povolené v kódu vytvořeném pomocí sady Visual Studio 2019 verze 16.5 a novějších verzí. Tento atribut se vztahuje pouze na konkrétní proměnnou, která ji následuje. Pokud chcete zakázat kontroly globálně, použijte možnost kompilátoru /Zc:tlsGuards- .