I have a std::vector
of std::variant
types allocated in stack. Since the size of each variant is variable. I am wondering what the memory layout of the vector is in stack.

- 3,542
- 5
- 34
- 60
-
6*Since the size of each variant is variable.* That is false. A variant will be as large or larger than its largest type. – NathanOliver Sep 27 '18 at 15:22
-
The size of an object is constant. An object of type `T` will have a certain size determined at compile time and all instances of `T` will have the exact same size. If an object appears to change size, it isn't Rather, the extra data is stored in dynamically allocated memory somewhere else and isn't part of the size. – François Andrieux Sep 27 '18 at 15:23
-
Also _...vector is in stack..."_ a vector on the stack is just a pointer and a size (or 2 pointers). The data contained in vector is on the heap. – Richard Critten Sep 27 '18 at 15:23
-
The size of a variant does not change. The variant is large enough to hold any of the variant types. But the size of the value representation of the variant can change. And the extra bits that does not participate to the value representation are called padding bits. A vector of variant may be filled with a lot of padding bits. A variant of vectors would have much less padding bit. – Oliv Sep 27 '18 at 17:09
1 Answers
C++ "std:variant" types are mimicking the good old C "union" types (or, more closely, the pascal tagged records), which means that they all have the same size, the only difference is that the std::variant values have additional information associated with them, this information tracks variant alternatives. Exact implementation for std::variant is platform-specific and I am afraid is not portable.
Visual C++ implementation for std::variant is very complicated (roughly 86 Kbytes of meta-template code). But we can guess some implementation details using simple tests:
#include <stdio.h>
#include <cstdint>
#include <variant>
template <typename T>
void Dump(T val)
{
printf("Size %zu: Data:",sizeof(val));
for (int i = 0; i < sizeof(val); ++i) printf(" %02X", (reinterpret_cast<std::uint8_t*>(&val))[i]);
printf("\n");
}
#pragma pack(push, 1)
typedef struct { std::variant<std::uint32_t, std::uint64_t> u; } dummy_variant_t;
#pragma pack(pop)
int main(int, char*[])
{
dummy_variant_t abc;
// _______________________ __ ?? ?? ?? ?? ?? ?? ?? <-- unknown info
// Size 16: Data: EF CD AB 89 67 45 23 01 01 13 EC 00 02 00 00 00
// ^variant data ^tag(uint64_t)
abc.u = static_cast<std::uint64_t>(0x123456789ABCDEF);
Dump(abc);
// ___________ xx xx xx xx __ ?? ?? ?? ?? ?? ?? ?? <-- unknown info
// Size 16: Data: 78 56 34 12 67 45 23 01 00 13 EC 00 02 00 00 00
// ^ ^garbage ^tag(uint32_t)
// |
// +variant data
abc.u = static_cast<std::uint32_t>(0x12345678);
Dump(abc);
return 0;
}
Here we see that this specific std::variant type roughly corresponds to:
struct variant_t
{
union
{
std::uint32_t m_Variant1;
std::uint64_t m_Variant2;
}
m_VariantData;
std::uint8_t m_Tag;
std::uint8_t m_Unknown[7];
};
So, I hope that this helps to nail your exact type. Pascal had these types long ago (almost from the beginning), see this excerpt from the freepascal manual

- 11
- 2