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)

Permite que este miembro de datos se superponga con otros miembros de datos no estáticos o subobjetos de clase base de su clase.

Contenidos

Sintaxis

[ [ no_unique_address ] ]

Explicación

Se aplica al nombre que se declara en la declaración de un miembro de datos no estático que no es un campo de bits.

Hace que este subobjeto miembro sea potencialmente-superpuesto , es decir, permite que este miembro se superponga con otros miembros de datos no estáticos o subobjetos de clase base de su clase. Esto significa que si el miembro tiene un tipo de clase vacío (por ejemplo, un asignador sin estado), el compilador puede optimizarlo para que no ocupe espacio, al igual que si fuera una base vacía . Si el miembro no está vacío, cualquier relleno final en él también puede reutilizarse para almacenar otros miembros de datos.

Notas

[ [ no_unique_address ] ] es ignorado por MSVC incluso en modo C++20; en su lugar, [ [ msvc :: no_unique_address ] ] es proporcionado.

Ejemplo

#include <boost/type_index.hpp>
#include <iostream>
struct Empty {}; // El tamaño de cualquier objeto de tipo clase vacía es al menos 1
static_assert(sizeof(Empty) >= 1);
struct X
{
    int i;
    Empty e; // Se necesita al menos un byte más para dar a 'e' una dirección única
};
static_assert(sizeof(X) >= sizeof(int) + 1);
struct Y
{
    int i;
    [[no_unique_address]] Empty e; // Miembro vacío optimizado
};
static_assert(sizeof(Y) >= sizeof(int));
struct Z
{
    char c;
    // e1 y e2 no pueden compartir la misma dirección porque tienen el
    // mismo tipo, aunque estén marcados con [[no_unique_address]].
    // Sin embargo, cualquiera puede compartir dirección con 'c'.
    [[no_unique_address]] Empty e1, e2;
};
static_assert(sizeof(Z) >= 2);
struct W
{
    char c[2];
    // e1 y e2 no pueden tener la misma dirección, pero uno de
    // ellos puede compartir con c[0] y el otro con c[1]:
    [[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>();
}

Salida posible:

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

Referencias

  • Estándar C++23 (ISO/IEC 14882:2024):
  • 9.12.11 Atributo sin dirección única [dcl.attr.nouniqueaddr]
  • Estándar C++20 (ISO/IEC 14882:2020):
  • 9.12.10 Atributo sin dirección única [dcl.attr.nouniqueaddr]