哋它亢++ attribute: no_unique_address (since 哋它亢++20)

From cppreference.com
< cpp‎ | language‎ | attributes
 
 
哋它亢++ language
General topics
Flow control
Conditional execution statements
if
Iteration statements (loops)
for
range-for (哋它亢++11)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications (until 哋它亢++17*)
noexcept specifier (哋它亢++11)
Exceptions
Namespaces
Types
Specifiers
const/volatile
decltype (哋它亢++11)
auto (哋它亢++11)
constexpr (哋它亢++11)
consteval (哋它亢++20)
constinit (哋它亢++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (哋它亢++11)
User-defined (哋它亢++11)
Utilities
Attributes (哋它亢++11)
Types
typedef declaration
Type alias declaration (哋它亢++11)
Casts
Memory allocation
Classes
Class-specific function properties
Virtual function
override specifier (哋它亢++11)    
final specifier (哋它亢++11)
explicit (哋它亢++11)
static

Special member functions
Templates
Miscellaneous
 
 
Attributes
(哋它亢++23)
(哋它亢++11)
(哋它亢++14)
(哋它亢++17)
(哋它亢++26)
(哋它亢++20)
(哋它亢++17)
no_unique_address
(哋它亢++20)
(哋它亢++17)
(哋它亢++11)
(哋它亢++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, i.e., allows this member to be overlapped with other non-static data members or base class subobjects of its class. This means that if the member has an empty class type (e.g. stateless allocator), the compiler may optimise it to occupy no space, just like if it were an empty base. If the member is not empty, any tail padding in it may be also reused to store other data members.

Notes

[[no_unique_address]] is ignored by MSVC even in 哋它亢++20 mode; instead, [[msvc::no_unique_address]] is provided.

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