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)

Позволяет этому члену данных перекрываться с другими нестатическими членами данных или подобъектами базовых классов его класса.

Содержание

Синтаксис

[ [ no_unique_address ] ]

Объяснение

Применяется к имени, объявляемому в объявлении нестатического члена данных, который не является битовым полем.

Делает этот член-подобъект потенциально-перекрывающимся , то есть позволяет этому члену перекрываться с другими нестатическими членами данных или подобъектами базовых классов его класса. Это означает, что если член имеет пустой тип класса (например, аллокатор без состояния), компилятор может оптимизировать его так, чтобы он не занимал места, как если бы он был пустым базовым классом . Если член не пуст, любое конечное заполнение в нем также может быть повторно использовано для хранения других членов данных.

Примечания

[ [ no_unique_address ] ] игнорируется MSVC даже в режиме C++20; вместо этого предоставляется [ [ msvc :: no_unique_address ] ]

Пример

#include <boost/type_index.hpp>
#include <iostream>
struct Empty {}; // Размер любого объекта пустого класса не менее 1
static_assert(sizeof(Empty) >= 1);
struct X
{
    int i;
    Empty e; // Требуется как минимум один дополнительный байт для уникального адреса 'e'
};
static_assert(sizeof(X) >= sizeof(int) + 1);
struct Y
{
    int i;
    [[no_unique_address]] Empty e; // Пустой член оптимизирован
};
static_assert(sizeof(Y) >= sizeof(int));
struct Z
{
    char c;
    // e1 и e2 не могут иметь одинаковый адрес, потому что они имеют
    // одинаковый тип, даже если они помечены [[no_unique_address]].
    // Однако любой из них может разделять адрес с 'c'.
    [[no_unique_address]] Empty e1, e2;
};
static_assert(sizeof(Z) >= 2);
struct W
{
    char c[2];
    // e1 и e2 не могут иметь одинаковый адрес, но один из
    // них может разделять с c[0], а другой с 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>();
}

Возможный вывод:

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

Ссылки

  • Стандарт C++23 (ISO/IEC 14882:2024):
  • 9.12.11 Атрибут no unique address [dcl.attr.nouniqueaddr]
  • Стандарт C++20 (ISO/IEC 14882:2020):
  • 9.12.10 Атрибут no unique address [dcl.attr.nouniqueaddr]