Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do std::variant implementations take more than 1 byte for variant of empty types?

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.

like image 718
NoSenseEtAl Avatar asked Sep 03 '21 19:09

NoSenseEtAl


People also ask

What is the size of an std :: variant?

So basically there's an internal variable in std::variant that has the size of 8 bytes (or less, but aligned to 8 bytes).


1 Answers

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.

like image 184
Nicol Bolas Avatar answered Nov 15 '22 15:11

Nicol Bolas