What Sean said.
Since I already typed it out before reading his response:
Could you explain, why a 3D/2D vector is an unfavourable?
Sure. First, let me clarify: I had two nested, abd you had three vectors nested, but speaking of the code logic, you had a "2D" vector of map cells (and each map cell had a vector), and I had a "1D" vector of map cells, and each map cell had a vector. I'm not arguing against each cell containing a vector.
Also, let me clarify that the "ouch" comment was the declaration:
std::vector<std::vector<std::vector<std::unique_ptr<mapObject>*>>> mMapObjectPointers;
I find that not very legible. Even if I was using the same thing, I'd rewrite it to show code intention more.
struct MapCell
{
std::vector<std::unique_ptr<MapObject*>> objects;
};
typedef std::vector<std::vector<MapCell>> MapCells;
MapCells mapCells;
Virtually the same thing (only one minor usage difference), just easier for me personally to read, especially when passing into functions by reference.
Alrighty, onward! So, setting aside the map cells, what's the differences between using:
std::vector<int> blah(Width*Height);
And:
std::vector<std::vector<int>> blah;
First, an std::vector<std::vector<>> isn't a 2D array. It's an array-of-arrays. This means that each "row" can be a different length... it doesn't enforce squareness/rectangleness! This is especially significant if you resize the arrays (for example, different maps having difference sizes) - you have to make sure you resize all of them; you have to keep them in sync.
Second, remember that std::vector<> allocates and manages a chunk of memory for you. Doing std::vector<std::vector<>> means you are allocating many smaller chunks of memory scattered throughout the RAM, instead of one chunk of memory (adding up to the same amount, total) in one location in the RAM. This *might* be slower, in some circumstances. In this situation, I wouldn't worry about it at all, as it probably doesn't matter in your case, but it's important to know as a "difference" between them.
Third, there are benefits to 1D vectors, and benefits to 2D vectors.
Now, let's suppose you had a class that actually was a 2D vector. We'll call it std::vector2D<> instead (no standard like that exists, but it'd be very easy to make).
The 1D benefits are, you can iterate from one end to the other really easily:
for(int i = 0; i < vector.size(); ++i) //Alternatively: for(Type &type : vector)
{
vector[i] = ...;
}
To do the same in 2D, you do:
for(int x = 0; x < width; ++x)
{
for(int y = 0; y < width; ++y)
{
vector[x][y] = ...;
}
}
More code for doing the same thing.
The benefit 2D arrays are indexing into them with 'x' and 'y', it more closely matches the mental model of your 2D board.
myMap[x][y] = ...;
But you can do the same thing with 1D arrays, by treating them as if they were 2D arrays:
myMap[(y * width) + x] = ....;
You get the best of both, with none of the other limitations.
The limitations (fragmentation of memory, manually keeping the row lengths in sync, extra code merely to iterate over every element) get worse and worse for each additional dimension you add. Three dimensions, four dimensions, whatever.
But you can treat a 1D array like an array of any number of dimensions you want, just by indexing into it how you like:
myMap[(z * width * height) + (y * width) + x] = ....; //Three dimensions
And you can wrap up the indexing into a helper function if you like.
Our memory (RAM) is one dimensional. Any 2D or 3D arrays are just mapping the indices to a 1D set of memory, the same way we are. Here, we're taking finer control over it so it maps the way we want, and so we can switch between 1D and 2D when we need (which we often do!).