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

From cppreference.com
< cpp‎ | language‎ | attributes
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
for
range-for (C++11)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications (until C++17*)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const/volatile
decltype (C++11)
auto (C++11)
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
explicit (C++11)
static

Special member functions
Templates
Miscellaneous
Attributes
(C++23)
(C++14)
(C++17)
(C++26)
(C++20)
(C++17)
(C++17)
(C++11)
no_unique_address
(C++20)
(C++20)

Allows this data member to be overlapped with other non-static data members or base class subobjects of its class.

Syntax

[[no_unique_address]]

Explanation

Applies to the name being declared in the declaration of a non-static data member that's not a bit-field.

Makes this member subobject potentially-overlapping empty base

Notes

[[no_unique_address]] is ignored by MSVC even in C++20 mode; instead, [[msvc::no_unique_address]]

Example

#include <iostream>
 
struct Empty {}; // empty class
 
struct X
{
    int i;
    Empty e;
};
 
struct Y
{
    int i;
    [[no_unique_address]] Empty e;
};
 
struct Z
{
    char c;
    [[no_unique_address]] Empty e1, e2;
};
 
struct W
{
    char c[2];
    [[no_unique_address]] Empty e1, e2;
};
 
int main()
{
    // the size of any object of empty class type is at least 1
    static_assert(sizeof(Empty) >= 1);
 
    // at least one more byte is needed to give e a unique address
    static_assert(sizeof(X) >= sizeof(int) + 1);
 
    // empty member optimized out
    std::cout << "sizeof(Y) == sizeof(int) is " << std::boolalpha 
              << (sizeof(Y) == sizeof(int)) << '\n';
 
    // e1 and e2 cannot share the same address because they have the
    // same type, even though they are marked with [[no_unique_address]]. 
    // However, either may share address with c.
    static_assert(sizeof(Z) >= 2);
 
    // e1 and e2 cannot have the same address, but one of them can share with
    // c[0] and the other with c[1]
    std::cout << "sizeof(W) == 2 is " << (sizeof(W) == 2) << '\n';
}

Possible output:

sizeof(Y) == sizeof(int) is true
sizeof(W) == 2 is true

References

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