Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The [[no_unique_address]] attribute is a C++20 feature applied to non-static data members, indicating that the member is not required to possess a distinct memory address within the enclosing object. This designates the member as a potentially-overlapping subobject, permitting the compiler to optimize the class’s memory layout by overlapping the member’s storage with other members or base classes.

Syntax

The attribute is placed immediately before the type specifier in the member declaration:
struct S {
    [[no_unique_address]] Type member_name;
};

Memory Layout Mechanics

When a member is marked with [[no_unique_address]], the compiler is permitted (but not required) to alter standard C++ object model rules regarding memory allocation based on the member’s type characteristics: 1. Empty Types If the member is an empty class type (a class with no non-static data members, no virtual functions, no virtual base classes, and no non-empty base classes), the compiler may allocate zero bytes of storage for it. The member may share its memory address with the enclosing object or with another subobject. 2. Non-Empty Types (Tail Padding) If the member is a non-empty type, it still occupies memory. However, if the type contains tail padding (unused bytes at the end of the object due to alignment requirements), the compiler may place subsequent data members of the enclosing class into that tail padding.

Code Visualization

The following example demonstrates the permitted mechanical effect on class size:
#include <iostream>

struct Empty {};

// Standard layout: 'e' takes 1 byte, plus 3 bytes of padding to align 'i'
struct StandardLayout {
    Empty e; 
    int i;   
}; // sizeof(StandardLayout) is typically 8

// Optimized layout: The compiler MAY optimize 'e' to occupy 0 bytes.
struct OptimizedLayout {
    [[no_unique_address]] Empty e;
    int i;
}; // sizeof(OptimizedLayout) may be 4 (compiler-dependent)

int main() {
    OptimizedLayout obj;
    // If optimized, &obj.e and &obj.i may evaluate to the exact same memory address.
}

Compiler Implementation Caveat (MSVC)

Because the C++ standard only permits this optimization without mandating it, compilers are free to ignore the attribute. Notably, to maintain Application Binary Interface (ABI) compatibility with older code, Microsoft Visual C++ (MSVC) ignores the standard [[no_unique_address]] attribute by default. To actually enforce this memory optimization in MSVC, developers must use the compiler-specific extension:
struct MsvcOptimized {
    [[msvc::no_unique_address]] Empty e;
    int i;
};

Technical Constraints and Rules

  • Object Identity: The C++ standard dictates that two subobjects of the same type cannot share the same memory address. If a class contains multiple [[no_unique_address]] members of the exact same empty type, the compiler must assign them distinct addresses, typically resulting in standard padding behavior for the subsequent members.
  • Bit-fields: The attribute cannot be applied to bit-field declarations.
  • Static Members: The attribute is strictly for non-static data members. Applying it to static members is ill-formed.
  • Address-of Operator: Taking the address of a [[no_unique_address]] member remains perfectly valid. If the compiler applied the optimization, the resulting pointer will simply point to the shared memory location.
  • ABI Compatibility: Because this attribute (or its MSVC-specific counterpart) changes the sizeof and memory layout of a struct or class, adding or removing it constitutes an ABI break. Code compiled with the attribute will be binary-incompatible with code compiled without it.
Master C++ with Deep Grasping Methodology!Learn More