为什么 std::variant 实现对空类型的变体占用超过 1 个字节?
Why do std::variant implementations take more than 1 byte for variant of empty types?
这主要是一些琐碎的问题,因为我怀疑我是否需要这种 space 储蓄。
在玩 godbolt 时,我注意到 std::variant
的 libstdc++ 和 libc++ 实现都需要超过 1 个字节来存储空结构的变体。
libstc++ 使用 2 个字节
libc++ 使用 8 个字节
我想优化这个是不值得的,但我想知道是否还有其他原因。特别是 std::variant
的标准措辞中是否存在阻止此优化的内容。
每个对象至少占用space的1个字节。计数器本身需要占用至少 1 个字节,但您还需要 space 用于对象的潜在选择。即使你使用union
,它仍然需要一个字节。而且不能和计数器是同一个字节。
现在,您可能认为 no_unique_address
可以拯救,允许成员 union
在所有 union
元素为空的情况下与计数器重叠。但请考虑以下代码:
empty_type e{};
variant<empty_type> ve{in_place_index<0>}; //variant now stores the empty type.
auto *pve = ve.get_if<0>(); //Pointer to an `empty_type`.
memcpy(pve, &e, sizeof(empty_type)); //Copying from one trivial object to another.
标准并没有说变体的成员是 variant
的“potentially-overlapping subojects”或其任何内部成员。因此,用户从一个琐碎的空对象到另一个对象执行 memcpy
是 100% 可以的。
如果与计数器重叠,它将覆盖计数器。所以不能和它重叠。
这主要是一些琐碎的问题,因为我怀疑我是否需要这种 space 储蓄。
在玩 godbolt 时,我注意到 std::variant
的 libstdc++ 和 libc++ 实现都需要超过 1 个字节来存储空结构的变体。
libstc++ 使用 2 个字节
libc++ 使用 8 个字节
我想优化这个是不值得的,但我想知道是否还有其他原因。特别是 std::variant
的标准措辞中是否存在阻止此优化的内容。
每个对象至少占用space的1个字节。计数器本身需要占用至少 1 个字节,但您还需要 space 用于对象的潜在选择。即使你使用union
,它仍然需要一个字节。而且不能和计数器是同一个字节。
现在,您可能认为 no_unique_address
可以拯救,允许成员 union
在所有 union
元素为空的情况下与计数器重叠。但请考虑以下代码:
empty_type e{};
variant<empty_type> ve{in_place_index<0>}; //variant now stores the empty type.
auto *pve = ve.get_if<0>(); //Pointer to an `empty_type`.
memcpy(pve, &e, sizeof(empty_type)); //Copying from one trivial object to another.
标准并没有说变体的成员是 variant
的“potentially-overlapping subojects”或其任何内部成员。因此,用户从一个琐碎的空对象到另一个对象执行 memcpy
是 100% 可以的。
如果与计数器重叠,它将覆盖计数器。所以不能和它重叠。