This is mostly trivia question, as I doubt that I will ever need this space saving.
While playing around on godbolt I noticed that both libstdc++ and libc++ implementations of std::variant
require more than 1 byte to store variant of empty structs.
libstc++ uses 2 bytes
libc++ uses 8 bytes
I presume it is just not worth the trouble to optimize this, but I wonder if there is any other reason. In particular is there something in standard wording for std::variant
that prevents this optimization.
So basically there's an internal variable in std::variant that has the size of 8 bytes (or less, but aligned to 8 bytes).
Every object takes up at least 1 byte of space. The counter itself needs to take up at least 1 byte, but you also need space for the potential choices of object. Even if you use a union
, it still needs to be one byte. And it can't be the same byte as the counter.
Now, you might think that no_unique_address
could just come to the rescue, permitting the member union
to overlap with the counter if all of the union
elements are empty. But consider this code:
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.
The standard does not say that the members of a variant are "potentially-overlapping subojects" of variant
or any of its internal members. Therefore, it is 100% OK for a user to do a memcpy
from one trivial empty object to the other.
Which will overwrite the counter if it were overlapping with it. Therefore, it cannot be overlapping with it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With