oh yes, the loops at the top are my catch all hack in case something goes wrong (however in the current build they are never called).
As for why I'm using vectors over structs is pretty simple (at least in my weirdly backwards way of thinking).
I have a list of chunks to build, this is just boolean true/false (reflecting which chunks to build, say we have local chunk 4 already built and we wish to build the rest, then we loop over it, push back false for the ones that are built and we push back true for the ones that aren't (this is entirely determined by the contents of the chunk metadata vector, if there's no chunk data there's no chunk at that location and as such it should be built).
Now how I intend to handle the chunk vector is that when a batch is unloaded I erase those, update with a new batch of chunks and top the struct off with new chunks (asynchronously, my code *should* be thread safe but I'm not going to implement multi-threaded terrain creation unless I really need the performance boost)
I think this image will explain it better
Essentially the logic follows as such:
Initiate the main function, instantiate the global scene manager pointer (along with device pointer and whatnot, all the standard irr stuff here, just with access from other files)
Instantiate the chunk manager, step through the entire build chain and have the local chunks loaded.
then the main function starts counting ticks, at 20 ticks it calls ChunkMgr::poll() which calls the buildList() and unloadList() (for now, I'll have more lists later like visibility lists to not load a bunch of chunks that cannot be observed at all (underground for example).
Anyway, as I was saying; the lists are polled sequentially, the unloadList talks to the scene manager to nuke old chunks, then the build list is called which builds an appropriate list of boolean values for which chunks to build, once this is done it talks to the chunk manager which then instructs the chunk class to build new chunks that are added to the active list of chunk objects.
Each chunk object then calls its mesh builder function to generate the meshes, it adds these meshes to the nodes list and this concludes the chunk building.
(there's a reason I included a flowchart, it makes the logic a bit easier to follow)
As for my reasons regarding using capacity, that's merely for debugging that it indeed allocated the capacity I wanted (reallocating the entire vector is expensive and theoretically something that can happen if I push_back an element, hence why I check to make sure the capacity is what I intended).
My reasons for pushing back early are also pretty simple, I do checks on elements at location n at arbitrary times and as such I need all elements to be accounted for, even if they are NULL (I actually check for that when building the chunks...)
Note: some parts of the images make a few assumptions (such as the fact that it's clear what data is sent where, mainly I'm just checking lists and populating lists, there's very little other data circulating so I didn't feel it was necessary to include the lists), if something is unclear it's probably because of that.