Namespaces
Variants

C++ attribute: no_unique_address (since C++20)

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)
(C++11) (until C++26)
(C++14)
(C++20)
(C++17)
(C++11)
no_unique_address
(C++20)
(C++20)

Erlaubt es diesem Datenmitglied, mit anderen nicht-statischen Datenmitgliedern oder Basisklassenunterobjekten seiner Klasse überlappt zu werden.

Inhaltsverzeichnis

Syntax

[ [ no_unique_address ] ]

Erklärung

Gilt für den Namen, der in der Deklaration eines nicht-statischen Datenelements deklariert wird, das kein Bitfeld ist.

Macht dieses Mitgliedssubobjekt potenziell-überlappend , d.h. erlaubt es, dass dieses Mitglied mit anderen nicht-statischen Datenelementen oder Basisklassen-Subobjekten seiner Klasse überlappt werden kann. Dies bedeutet, dass wenn das Mitglied einen leeren Klassentyp hat (z.B. zustandsloser Allokator), der Compiler es so optimieren kann, dass es keinen Speicherplatz belegt, genau wie bei einer leeren Basisklasse . Wenn das Mitglied nicht leer ist, kann dessen abschließende Auffüllung ebenfalls wiederverwendet werden, um andere Datenelemente zu speichern.

Hinweise

[ [ no_unique_address ] ] wird von MSVC selbst im C++20-Modus ignoriert; stattdessen wird [ [ msvc :: no_unique_address ] ] bereitgestellt.

Beispiel

#include <boost/type_index.hpp>
#include <iostream>
struct Empty {}; // Die Größe eines beliebigen Objekts vom Typ einer leeren Klasse ist mindestens 1
static_assert(sizeof(Empty) >= 1);
struct X
{
    int i;
    Empty e; // Mindestens ein weiteres Byte wird benötigt, um 'e' eine eindeutige Adresse zu geben
};
static_assert(sizeof(X) >= sizeof(int) + 1);
struct Y
{
    int i;
    [[no_unique_address]] Empty e; // Leeres Mitglied optimiert
};
static_assert(sizeof(Y) >= sizeof(int));
struct Z
{
    char c;
    // e1 und e2 können nicht dieselbe Adresse teilen, da sie denselben
    // Typ haben, selbst wenn sie mit [[no_unique_address]] markiert sind.
    // Allerdings kann jede Adresse mit 'c' teilen.
    [[no_unique_address]] Empty e1, e2;
};
static_assert(sizeof(Z) >= 2);
struct W
{
    char c[2];
    // e1 und e2 können nicht dieselbe Adresse haben, aber eines
    // von ihnen kann mit c[0] und das andere mit c[1] teilen:
    [[no_unique_address]] Empty e1, e2;
};
static_assert(sizeof(W) >= 2);
template <typename T>
void print_size_of()
{
    using boost::typeindex::type_id;
    std::cout << "sizeof(" << type_id<T>() << ") == " << sizeof(T) << '\n';
}
int main()
{
    print_size_of<Empty>();
    print_size_of<int>();
    print_size_of<X>();
    print_size_of<Y>();
    print_size_of<Z>();
    print_size_of<W>();
}

Mögliche Ausgabe:

sizeof(Empty) == 1
sizeof(int) == 4
sizeof(X) == 8
sizeof(Y) == 4
sizeof(Z) == 2
sizeof(W) == 3

Referenzen

  • C++23-Standard (ISO/IEC 14882:2024):
  • 9.12.11 No-unique-address-Attribut [dcl.attr.nouniqueaddr]
  • C++20-Standard (ISO/IEC 14882:2020):
  • 9.12.10 No-unique-address-Attribut [dcl.attr.nouniqueaddr]