So I'm working with this struct type with variable length array member, like this:
struct Entry;
struct Data {
int members;
size_t entries_size;
Entry entries[1];
};
The entries_size
member is the actual size of the entires
array, it is only known when read from network. The problem is that I'd like to use it in a std::variant
among other network data types, how can I put it into a std::variant
with the footprint of the whole data object, without dangling pointers flying around?
std::variant<Data, OtherData2, OhterData3...> v;
CodePudding user response:
This cannot be done in C , C simply does not work this way on a fundamental level.
In C all objects have a defined type, and a defined, fixed size. You are using a common C-like approach of manually over-allocating memory so that there can be additional Entry
s in memory, after the pro-forma one.
Taking specific, strict, well-controlled steps allows this to be done without breaking (most) "the rules" (but only assuming that Entry
is trivial, of course, which is unclear).
However introducing a variant into the mix is pretty much a showstopper. A std::variant
is (certainly) not a trivial POD. This particular showstopper can, potentially, be worked around using placement new after over-allocating a calculated amount of memory for this kind of a franken-variant.
However once past this hurdle the next one is insurmountable: C gives you no guarantees, whatsoever, as to a variant's internal layout. After all, a variant must keep track of which variant value is constructed, and the additional metadata for all of that can appear either before or after the reserved space for the value of the variant. It is not specified. Game over.
CodePudding user response:
As has been pointed out, this is not legal C . It just wont work this way. However, if the amount of entries is bound, it might be possible to do this:
template <std::size_t N>
struct Data {
int members;
static constexpr std::size_t entries_size = N;
Entry entries[N];
}; // Of couse, you might want to use std::array<Entry,N> instead!
// ...
std::variant<Data<2>, Data<8>, Data<32>> example;
This, of course, is highly situational. If you know the incoming data will fall into either 2, 8 or 32 entries, you can specify these at compile time. If the amount of entries is completely variable, with no guarantees, use std::vector
. That's what it's for.