Why is this an issue?
In C++ every independent object needs to have a unique address, which implies that its size cannot be null. Sub-objects of another object, however,
do not have this constraint. Empty base class subobjects usually don’t take any space in the final object, but empty member variables, by default,
take some space, at least one byte. The impact of the final size of the object may be even larger, due to padding and alignment requirements.
C++ 20 introduces the [[no_unique_address]]
attribute. It indicates that preserving the uniqueness of address guarantee is not
important for the decorated member variable, and if the variable type is empty, no storage needs to be reserved for it in the class.
If the type is not empty, this attribute is still valid, and has no effect. This allows to place this attribute on dependant member variables in
template classes, and have the exact behavior depend on the actual template parameters.
This rule raises an issue on each member of a class that has an empty or potentially empty (in case of templates) type and does not have
[[no_unique_address]]
attribute.
Note: This rule is disabled on Windows because [[no_unique_address]]
isn’t well supported by MSVC and Clang on
this platform.
Noncompliant code example
struct Empty {};
struct Wrapped {
int* ptr;
Empty e; // Noncompliant
}; // sizeof(Wrapped) is > sizeof(int*)
template<typename K, typename V, typename Hash, typename Equal>
class HashMap {
/* ... */
Hash hash; // Noncompliant if HashMap is instantiated with an empty Hash
Equal equal; // Noncompliant if HashMap is instantiated with an empty Equal
};
Compliant solution
struct Empty {};
struct Wrapped {
int* ptr;
[[no_unique_address]] Empty e;
}; // sizeof(Wrapped) can be equal to sizeof(int*)
template<typename K, typename V, typename Hash, typename Equal>
class HashMap {
/* ... */
[[no_unique_address]] Hash hash;
[[no_unique_address]] Equal equal;
};
Exceptions
This rule does not apply to fields whose class has a non-default alignment.