考虑以下三个struct
:
class blub {
int i;
char c;
blub(const blub&) {}
};
class blob {
char s;
blob(const blob&) {}
};
struct bla {
blub b0;
blob b1;
};
在int
4字节的典型平台上,大小,对齐方式和总填充1如下:
struct size alignment padding
-------- ------ ----------- ---------
blub 8 4 3
blob 1 1 0
bla 12 4 6
即使大小为1 的原则上可以“适合”的填充,在blub
和blob
成员的存储之间也没有重叠。blob
blub
C ++ 20引入了该no_unique_address
属性,该属性允许相邻的空成员共享同一地址。它还明确允许上述使用一个成员的填充存储另一个成员的方案。来自cppreference(重点是我的):
指示此数据成员不必具有与该类的所有其他非静态数据成员不同的地址。这意味着,如果成员具有空类型(例如,无状态的分配器),则编译器可以对其进行优化以使其不占用任何空间,就像其为空基一样。如果成员不为空,则其中的任何尾部填充也可以重新用于存储其他数据成员。
确实,如果我们在上使用此属性blub b0
,则bla
drop 的大小为to 8
,因此blob
确实存储在blub
godbolt上看到的中。
最后,我们要问我的问题:
no_unique_address
对于无法平凡复制的对象,标准(C ++ 11到C ++ 20)中的哪些文本不使用来防止这种重叠?
我需要从上面排除琐碎的可复制(TC)对象,因为对于TC对象,允许将其std::memcpy
从一个对象转移到另一个对象,包括成员子对象,并且如果存储重叠,则这会损坏(因为全部或部分存储)因为相邻成员将被覆盖)2。
1我们将递归简单地计算为结构大小与其所有组成成员的大小之差。
2这就是为什么我定义了复制构造函数的原因:make blub
而blob
不是琐碎的copyable。