如何处理 [[no_unique_address]] 是实现定义的吗?

Is it implementation-defined that how to deal with [[no_unique_address]]?

以下摘自cppref but reduced to demo:

#include <iostream>
 
struct Empty {}; // empty class

struct W
{
    char c[2];
    [[no_unique_address]] Empty e1, e2;
};
 
int main()
{ 
    std::cout << std::boolalpha;

    // 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';
}

文档说输出可能是:

sizeof(W) == 2 is true

但是gcc和clang的输出如下:

sizeof(W) == 2 is false

实现定义了如何处理 [[no_unique_address]]?

参见[intro.object]/8

An object has nonzero size if ... Otherwise, if the object is a base class subobject of a standard-layout class type with no non-static data members, it has zero size. Otherwise, the circumstances under which the object has zero size are implementation-defined.

空基 class 优化成为 C++11 中标准布局 classes 的强制要求(参见 here 讨论)。空成员优化从来都不是强制性的。如您所料,它是实现定义的。

是的,no_unique_address 的几乎所有方面都是实现定义的。它是一种允许进行优化的工具,而不是强制执行它们。

话虽如此,当您尝试拥有两个 相同类型 的子对象时,您永远不应该假设 no_unique_address 会起作用。标准还是。虽然编译器可以通过彻底重新排序成员来为这些空子对象分配不同的地址……但他们几乎不会那样做。

合理利用 no_unique_address 优化的最佳做法是永远不要有两个相同类型的子对象,并尝试将所有可能为空的成员放在 前面 。也就是说,您应该期望实现将空 no_unique_address 成员分配给下一个成员的偏移量(或整个包含结构的偏移量)。