Hi! I reckon that to handle for example some texture asset in a game, the following would be a more or less elegant C++ way (not counting that everything is public here) :
struct Texture
{
int width, height, pixel_size;
std::vector<char> pix;
};
Then I could create an instance "tex", get the image width, height, and bytes per pixel value from the image file, set the appropriate fields, then tex.pix.resize() accordingly and fill the vector with the pixel data. Anything that processes the pixels (OpenGL for example) could then use &tex.pix[0] as a base pointer.
However, after I allocate dynamically for the Texture, the pixel array will need to be allocated separately by std::vector. I would like to avoid this (some reasons are below), instead, I would like the array be part of the struct, which is hard, because my array does not have a fixed size. There is something in C99 called "flexible array members", which allows the following syntax:
struct Texture
{
int width, height, pixel_size;
char pix[];
};
but only if the array without given size is at the end of the struct. This is only in C99, not in the C++ standard, but gcc apparently supports it for C++. Another trick is to use an array of 1 element, like this:
struct Texture
{
int width, height, pixel_size;
char pix[1];
};
In this case, one could use it like this:
// obtain image width, height and bytes per pixel,
// and store them in local variables w, h, n
char * ptr = new char[sizeof(Texture) - 1 + w*h*n]; // pix array will have w*h*n elements
Texture * tex = reinterpret_cast<Texture*>(ptr);
tex->width = w;
tex->height = h;
tex->pixel_size = n;
// fill tex->pix[] with pixel data
// use the texture
delete [] ptr;
My first question: is it safe? Some say that it leads to undefined behaviour when a fixed (here: 1) size array is overindexed, because higher optimisation levels could lead to something unwanted. But I've seen an excellent open source C++ game use this technique at one point (allocating with calloc() instead of new char[]), so it should work (most of the time?).
Some reasons I desire something like this are:
1. "Data locality" i.e. I would like the metadata be close to the actual data in memory, so that it is not necessary to follow another pointer to a potentially far away location.
2. I would like to keep the asset data structures (such as this Texture example) as plain old C data (without non-trivial destructors or virtual functions etc.), to avoid the overhead of another allocation/deallocation, or the risk of leaks caused by missed destructor calls. I wouldn't really take advantage of the dynamically-expanding std::vector anyway: the size of the asset doesn't change after loading. A simple character array is almost good enough for me: if the asset is a long text, I don't need anything else, but for textures I also need width, height, bytes per pixel, for PCM data I need sample size, number of channels etc.
In short, an asset in most part consists of a large byte sequence, but in many cases I would like to smuggle some metadata in front of it.
How should I do this? Is there anything more suited than structs with flexible array members? Or should I follow a completely different approach?