5

以下摘自cppref但简化为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 为真

但是,gcc 和 clang 的输出如下:

sizeof(W) == 2 为假

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

4

2 回答 2

6

[intro.object]/8

如果对象具有非零大小... 否则,如果该对象是标准布局类类型的基类子对象且没有非静态数据成员,则它的大小为零。否则,对象大小为零的情况由实现定义。

在 C++11 中,空基类优化成为标准布局类的强制要求(参见此处进行讨论)。空成员优化从来都不是强制性的。正如您所怀疑的,它是实现定义的。

于 2021-12-01T16:12:20.087 回答
6

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

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

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

于 2021-12-01T16:13:19.770 回答