C99 adds a feature called flexible array members. If the final member of a struct is an array with no length (blank rather than zero), you're allowed to use the array to access memory after the struct with the appropriate subscripts.
t_packet *packet = malloc(sizeof(*packet) + payload_size);I'd class that as a valid quibble, if my interpretation is correct, but a quibble nonetheless. The general intent is clear enough from the standard, I think: http://port70.net/~nsz/c/c11/n1570.html#6.7.2.1p18
Further reading on the subject of undefined behaviour (apropos of nothing in particular): http://port70.net/~nsz/c/c11/n1570.html#3.4.3p1, http://robertoconcerto.blogspot.co.uk/2010/10/strict-aliasin..., https://groups.google.com/forum/#!msg/boring-crypto/48qa1kWi..., http://blog.metaobject.com/2014/04/cc-osmartass.html
template <int N>
struct ion_system_heap {
struct ion_heap heap;
struct ion_page_pool *pools[N];
};
But that is not quite the same thing since ion_system_heap<10> and ion_system_heap<20> won't be the same type and makes it super hard to use. And a whole bunch of other problems like not knowing how many pages you want to allocate at compile time.Yes you can just use a vector for "pools" but that allocates it on the heap instead of in the struct.
It solved it by wrapping with a superclass that you downcast from. You won't be able to work with them by value due to object slicing but you can still have a vector of pointers:
vector<Panda_without_bamboo*> pandas;
I am not sure how to do the downcasting though. Assuming the classes look like this: public Panda_without_bamboo
{
int bambooCount;
}
template<std::size_t N>
class Panda_with_bamboo : public Panda_without_bamboo
{
int a;
int b;
Bamboo bamboo[N];
}
You can't really do: static_cast<Panda<pandas[0].bambooCount>*>(pandas[0])
So it does seem like using flexible array members (first answer in that stackoverflow and the topic discussed in this submission) is a cleaner solution if you need contiguous allocation: http://www.codeatcpp.com/2007/10/dynamic-array-template.htmlIf you need contiguous memory though this is likely a terrible way to go about it since you are not only having to dereference pointers that could go anywhere, but each one will mean a separate heap allocation which will be slow for small objects and not scale with concurrency.
Edit: But casting the allocated memory around to a struct type might violate aliasing rules...
uint16_t array[] = { 1, 2, 3, 4 }; cout << "Hello World " << 3[array] << endl;
are valid and well defined. Part of what makes memory access validation such a pain in the ass in C++ is that no attempts are really made at specifying rules for how you can come up with memory locations; just rules on which locations you can read and write from. You can do things like "((int)rand()) = 2", and nothing in the standard says this is an invalid thing to do, so long as you are lucky enough for rand() to point somewhere allocated.