Freigeben über


Attribute in C++

Der C++-Standard definiert allgemeine Attribute. Außerdem ermöglicht er Compilerherstellern, eigene Attribute in einem anbieterspezifischen Namespace zu definieren. Compiler sind jedoch nur erforderlich, um die im Standard definierten Attribute zu erkennen.

In einigen Fällen überschneiden sich Standardattribute mit compilerspezifischen __declspec-Parametern. In Microsoft C++ können Sie das [[deprecated]]-Attribut anstelle von __declspec(deprecated) verwenden. Das [[deprecated]]-Attribut wird von jedem konformen Compiler erkannt. Für alle anderen __declspec-Parameter wie dllimport und dllexport gibt es bisher keine Attributentsprechung. Daher müssen Sie die Syntax __declspec weiterhin verwenden . Attribute haben keinen Einfluss auf das Typsystem, und sie ändern die Bedeutung eines Programms nicht. Compiler ignorieren Attributwerte, die sie nicht erkennen.

Visual Studio 2017, Version 15.3 und höher (verfügbar mit /std:c++17 und höher): Im Bereich einer Attributliste können Sie den Namespace für alle Namen mit einer einzelnen using-Einführung angeben:

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

C++-Standardattribute

In C++11 bieten Attribute eine standardisierte Möglichkeit, um zusätzliche Informationen zu C++-Konstrukten (unter anderem Klassen, Funktionen, Variablen und Blöcke) anzumerken. Attribute können anbieterspezifisch sein. Ein Compiler kann anhand dieser Informationen Informationsmeldungen generieren oder spezielle Logik beim Kompilieren des attributierten Codes anwenden. Der Compiler ignoriert alle nicht erkannten Attribute. Deshalb können Sie mit dieser Syntax keine eigenen benutzerdefinierten Attribute definieren. Attribute werden in doppelte eckige Klammern eingeschlossen:

[[deprecated]]
void Foo(int);

Attribute sind eine standardisierte Alternative zu anbieterspezifischen Erweiterungen wie #pragma-Anweisungen, __declspec() (Visual C++) oder __attribute__ (GNU). Für die meisten Zwecke müssen Sie jedoch weiterhin die anbieterspezifischen Konstrukte verwenden. Der Standard gibt derzeit die folgenden Attribute an, die ein konformer Compiler erkennen sollte.

[[carries_dependency]]

Das [[carries_dependency]]-Attribut gibt an, dass die Funktion die Reihenfolge der Datenabhängigkeiten für die Threadsynchronisierung weitergibt. Das Attribut kann auf einen oder mehrere Parameter angewendet werden, um anzugeben, dass das übergebene Argument eine Abhängigkeit im Funktionstext enthält. Das Attribut kann auf die Funktion selbst angewendet werden, um anzugeben, dass der Rückgabewert eine Abhängigkeit aus der Funktion enthält. Der Compiler kann mithilfe dieser Informationen einen effizienteren Code generieren.

[[deprecated]]

Visual Studio 2015 und höher: Das [[deprecated]]-Attribut gibt an, dass eine Funktion nicht zur Verwendung vorgesehen ist, oder dass es sie in künftigen Versionen einer Bibliotheksschnittstelle möglicherweise nicht mehr gibt. Das [[deprecated]]-Attribut kann auf die Deklaration einer Klasse, einen typedef-Namen, eine Variable, ein nicht statisches Datenelement, eine Funktion, einen Namespace, eine Enumeration, einen Enumerator oder eine Vorlagenspezialisierung angewendet werden. Der Compiler kann mit diesem Attribut eine Informationsmeldung generieren, wenn Clientcode versucht, die Funktion aufzurufen. Wenn der Microsoft C++-Compiler die Verwendung eines [[deprecated]]-Elements erkennt, löst er die Compilerwarnung C4996 aus.

[[fallthrough]]

Visual Studio 2017 und höher: (Verfügbar mit /std:c++17 und höher.) Das [[fallthrough]]-Attribut kann im Kontext von switch-Anweisungen verwendet werden, um den Compiler (oder jeden, der den Code liest) darauf hinzuweisen, dass das Fall-Through-Verhalten beabsichtigt ist. Der Microsoft C++-Compiler gibt derzeit keine Warnung Fall-Through-Verhalten aus. Daher hat dieses Attribut keine Auswirkungen auf das Compilerverhalten.

[[likely]]

Visual Studio 2019, Version 16.6 und höher: (Verfügbar mit /std:c++20 und höher.) Das [[likely]]-Attribut enthält einen Hinweis für den Compiler, dass der Codepfad für die attributierte Bezeichnung oder Anweisung mit höherer Wahrscheinlichkeit ausgeführt wird als Alternativen. Im Microsoft-Compiler markiert das [[likely]]-Attribut Blöcke als „Hot Code“, was eine interne Optimierungsbewertung schrittweise erhöht. Die Bewertung wird bei einer Geschwindigkeitsoptimierung stärker erhöht als bei einer Größenoptimierung. Die Nettobewertung wirkt sich auf die Wahrscheinlichkeit von Inlining-, Loop-Unrolling- und Vektorisierungsoptimierungen aus. Die Wirkung von [[likely]] und [[unlikely]] ähnelt der profilgesteuerten Optimierung, ist jedoch vom Umfang her auf die aktuelle Übersetzungseinheit beschränkt. Die Optimierung der Blockneuanordnung ist für dieses Attribut noch nicht implementiert.

[[maybe_unused]]

Visual Studio 2017, Version 15.3 und höher: (Verfügbar mit /std:c++17 und höher.) Das [[maybe_unused]]-Attribut gibt an, dass eine Variable, Funktion, Klasse, Typedef, Enumeration, Vorlagenspezialisierung oder ein statischer Datenmember möglicherweise absichtlich nicht verwendet wird. Der Compiler gibt keine Warnung aus, wenn eine als [[maybe_unused]] markierte Entität nicht verwendet wird. Eine Entität, die ohne das Attribut deklariert wird, kann später mit dem Attribut neu deklariert werden und umgekehrt. Eine Entität wird als markiert betrachtet, nachdem ihre erste als [[maybe_unused]] markierte Deklaration analysiert wurde, sowie für den Rest der aktuellen Übersetzungseinheit.

[[nodiscard]]

Visual Studio 2017, Version 15.3 und höher: (Verfügbar mit /std:c++17 und höher.) Gibt an, dass der Rückgabewert einer Funktion nicht verworfen werden soll. Löst die Warnung C4834 aus, wie in diesem Beispiel gezeigt:

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

Das [[noreturn]]-Attribut gibt an, dass eine Funktion niemals zurückgegeben wird, d. h., sie löst immer eine Ausnahme aus oder wird beendet. Der Compiler kann seine Kompilierungsregeln für [[noreturn]]-Entitäten anpassen.

[[unlikely]]

Visual Studio 2019, Version 16.6 und höher: (Verfügbar mit /std:c++20 und höher.) Das [[unlikely]]-Attribut enthält einen Hinweis für den Compiler, dass der Codepfad für die attributierte Bezeichnung oder Anweisung mit geringerer Wahrscheinlichkeit ausgeführt wird als Alternativen. Im Microsoft-Compiler markiert das [[unlikely]]-Attribut Blöcke als „Cold Code“, was eine interne Optimierungsbewertung schrittweise verringert. Die Bewertung wird bei einer Größenoptimierung stärker verringert als bei einer Geschwindigkeitsoptimierung. Die Nettobewertung wirkt sich auf die Wahrscheinlichkeit von Inlining-, Loop-Unrolling- und Vektorisierungsoptimierungen aus. Die Optimierung der Blockneuanordnung ist für dieses Attribut noch nicht implementiert.

Microsoft-spezifische Attribute

[[gsl::suppress(<tag> [, justification: <narrow-string-literal>])]]

<tag> ist eine Zeichenfolge, die den Namen der zu unterdrückenden Regel angibt. Im optionalen justification Feld können Sie erklären, warum eine Warnung deaktiviert oder unterdrückt wird. Dieser Wert wird in der SARIF-Ausgabe angezeigt, wenn die /analyze:log:includesuppressed Option angegeben wird. Sein Wert ist ein UTF-8-codiertes schmales Zeichenfolgenliteral. Das [[gsl::suppress]] Attribut ist in Visual Studio 2022 Version 17.14 und höher verfügbar.

Mit dem Microsoft-spezifischen [[gsl::suppress]]-Attribut werden Warnungen von Prüfungen unterdrückt, die Regeln der Guidelines Support Library (GSL) im Code erzwingen. Betrachten Sie beispielsweise den folgenden Codeausschnitt:

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

In dem Beispiel werden die folgenden Warnungen ausgelöst:

  • C26494 (Typregel 5: Ein Objekt immer initialisieren.)

  • C26485 (Begrenzungsregel 3: Kein Array zum Zeigerzerfall.)

  • C26481 (Begrenzungsregel 1: Keine Zeigerarithmetik verwenden. Stattdessen „span“ verwenden.)

Die ersten beiden Warnungen werden ausgelöst, wenn Sie diesen Code mit dem installierten und aktivierten CppCoreCheck-Codeanalysetool kompilieren. Die dritte Warnung wird jedoch aufgrund des Attributs nicht ausgelöst. Sie können das gesamte Begrenzungsprofil unterdrücken, indem Sie [[gsl::suppress("bounds")]] schreiben, ohne eine bestimmte Regelnummer einzugeben. Die C++-Kernrichtlinien sind so konzipiert, dass Sie besseren und sichereren Code schreiben können. Das suppress-Attribut erleichtert das Deaktivieren unerwünschter Warnungen.

[[msvc::flatten]]

Das Microsoft-spezifische [[msvc::flatten]]-Attribut ist [[msvc::forceinline_calls]] sehr ähnlich und kann an denselben Stellen und auf die gleiche Weise verwendet werden. Der Unterschied besteht darin, dass [[msvc::flatten]] rekursiv [[msvc::forceinline_calls]] für alle Aufrufe in dem Bereich ausführt, auf den es angewendet wird, bis keine Aufrufe verbleiben. Dies kann hinsichtlich der resultierende Zunahme des Codeumfangs der Funktion oder des Compilerdurchsatzes Folgen haben, die Sie manuell behandeln müssen.

[[msvc::forceinline]]

Wenn das Microsoft-spezifische [[msvc::forceinline]]-Attribut vor einer Funktionsdeklaration platziert wird, hat es die gleiche Bedeutung wie __forceinline.

[[msvc::forceinline_calls]]

Das Microsoft-spezifische [[msvc::forceinline_calls]]-Attribut kann in einer Anweisung oder einem Block platziert werden oder davor. Die Inlineheuristik versucht, [[msvc::forceinline]] für alle Aufrufe in dieser Anweisung oder diesem Block auszuführen:

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

Der erste Aufruf von foo und beide Aufrufe von bar werden so behandelt, als würden sie mit __forceinline deklariert werden. Der zweite Aufruf von foo wird nicht als __forceinline behandelt.

[[msvc::intrinsic]]

Das [[msvc::intrinsic]]-Attribut bringt für die Funktion, auf die es angewendet wird, drei Einschränkungen mit sich:

  • Die Funktion kann nicht rekursiv sein; ihr Textkörper darf nur über eine return-Anweisung mit einem static_cast vom Parametertyp bis zum Rückgabetyp verfügen.
  • Die Funktion kann nur einen einzigen Parameter akzeptieren.
  • Die Compileroption /permissive- ist erforderlich. (/std:c++20 und spätere Optionen schließen /permissive- standardmäßig ein.)

Das Microsoft-spezifische [[msvc::intrinsic]]-Attribut weist den Compiler an, inline eine Metafunktion zu verwenden, die als benannte Umwandlung vom Parametertyp in den Rückgabetyp fungiert. Wenn das Attribut in einer Funktionsdefinition vorhanden ist, ersetzt der Compiler alle Aufrufe dieser Funktion durch eine einfache Umwandlung. Das [[msvc::intrinsic]]-Attribut ist in Visual Studio 2022, Version 17.5 Preview 2 und höher, verfügbar. Dieses Attribut gilt nur für die darauf folgende bestimmte Funktion.

Beispiel

In diesem Beispielcode veranlasst das [[msvc::intrinsic]]-Attribut, das auf die my_move-Funktion angewendet wird, den Compiler zum Ersetzen von Aufrufen der Funktion durch die inline im Textkörper enthaltene statische Umwandlung:

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

Wenn das Microsoft-spezifische [[msvc::noinline]]-Attribut vor einer Funktionsdeklaration platziert wird, hat es die gleiche Bedeutung wie __declspec(noinline).

[[msvc::noinline_calls]]

Das Microsoft-spezifische [[msvc::noinline_calls]]-Attribut wird genau so verwendet wie [[msvc::forceinline_calls]]. Es kann vor einer Anweisung oder einem Block platziert werden. Anstatt die Inlineverwendung aller Aufrufe in diesem Block zu erzwingen, deaktiviert es das Inlining für den Bereich, auf den es angewendet wird.

[[msvc::no_tls_guard]]

Das Microsoft-spezifische [[msvc::no_tls_guard]]-Attribut deaktiviert die Überprüfung der Initialisierung beim ersten Zugriff auf threadlokale Variablen in DLLs. Die Überprüfungen sind standardmäßig in Code aktiviert, der mit Visual Studio 2019, Version 16.5 und höheren Versionen erstellt wurde. Dieses Attribut gilt nur für die darauf folgenden bestimmten Variablen. Verwenden Sie die Compileroption /Zc:tlsGuards-, um Überprüfungen global zu deaktivieren.