Creating a matrix with unique pointers and 'empty'cells - c++

I'm quite new to coding and am running into a problem. I'm working with matrices and previously I had only integers inside them representing the state of a cell. I initiliazed my grid in the following way:
const int N = 50; // Grid size
// 3 vectors for 3 different antibiotics
std::vector<std::vector<int> > gridAB1(N, std::vector<int>(N));
std::vector<std::vector<int> > gridAB2(N, std::vector<int>(N));
std::vector<std::vector<int> > gridAB3(N, std::vector<int>(N));
After which I would change the 0's in these grids at random positions to a certain value.
Now I'm moving into a more complex setting where cell state can't be defined as easily as just an integer. I will create a class or struct to represent the cells. I was now recommended to have a grid with at positions (unique) pointers pointing to this struct or class. However I'm very unsure of how to initialize this and how to define between empty places in the grid and places with a cell cause only at a few places in the grid should there actually be a pointer pointing to the struct or class, the rest of the grid would just be "empty". If anyone has any tips or ways of achieving something like this that would be great.

If your data is a class/struct named Cell then the analog to your first example would be
#include <memory>
#include <vector>
std::vector<std::vector<std::unique_ptr<Cell>>> grid(N, std::vector<std::unique_ptr<Cell>>(N));
In this case you can "initialize" a Cell by constructing it such as
grid[i][j] = std::make_unique<Cell>(args);
or modify a cell similarly
grid[i][j]->some_method();
Though if your Cell is "simple" (small, POD, trivially copyable and moveable, etc) I would just store by value
std::vector<std::vector<Cell>> grid(N, std::vector<Cell>(N));
Then you'd need some way to determine if the Cell was "filled" yet, like keeping a bool member on the Cell like initialized or something. But the matrix access would look the same
grid[i][j] = Cell(args);
grid[i][j].some_method();

Related

Storing objects in 2 dimensional sprite matrix in c++

I want to store a list of tiles (pointers to objects of class "Sprite") in a two dimensional vector.
Currently I'm storing all the sprites of my tilemap in a vector.
std::vector<Sprite*> _tiles;
Now I need to get all the neighbored tiles and I thought it be easier, to store my sprites in a 2d matrix (vector in vector) to do those caluclations.
But I can't figure out how to do that.
Header:
private:
std::vector<std::vector<Sprite*>> matrix;
C++ File:
vectorMatrix::vectorMatrix(int columns, int rows) { }
vectorMatrix::~vectorMatrix() { }
void vectorMatrix::addCellAt(int x, int y, Sprite* sprite) {
std::vector< std::vector<Sprite*> > matrix;
matrix[x][y].push_back(sprite);
}
But I get an error message if I use two index operators.
std::vector< std::vector<Sprite*> > matrix;
This is an empty std::vector of of std::vector, and as others have pointed out, it's no longer the data member matrix.
Since it's empty, it's not possible to do matrix[0] - get the first row, matrix[1] - get the second row... You can however allocate the size of the matrix in your constructor first -- e.g. This will give you a rows*columns matrix
vectorMatrix::vectorMatrix(int columns, int rows)
: matrix(rows, std::vector<Sprite*>(columns))
{
}
And then you can set the xth and yth element to the corresponding Sprite*, and of course x and y should be smaller than rows and columns
matrix[x][y] = sprite;
And don't declare matrix again inside the addCellAt, You can use the data members directly anywhere inside the class.
Why do you think it's a good idea to make your matrix a vector-of-vectors? True, this will "work" in the sense that vec_of_vec_matrix[i][j] will return the right thing, but it's somewhat cumbersome and inefficient.
Instead, consider basing your class on a single vector - of all data, as done in this answer (and probably in many libraries). Element access will be something like (for column-major data):
Sprite*& Matrix::operator()(size_t i, size_t j)
{
return mData[i * num_columns + j];
}
You could even arrange with map[x][y] to work, using a row proxy class.
Three problems:
You declare a local variable matrix inside the function, which shadows the member variable.
If the size of the vectors is not set to include the x and y indexes then you will go out of bounds.
matrix[x][y] is not itself a vector, it's an element that you can assign directly:
matrix[x][y] = sprite;
Remember to consider problem 2 before doing this.

In C++, How do I store values into a vector that is inside of a vector when the two vectors are of different types?

I am writing a program where I need to use the following data structure:
struct shape
{
std::vector<float> verts; // contains the x & y values for each vertex
char type; // the type of shape being stored.
float shapeCol[3]; // stores the color of the shape being stored.
float shapeSize; // stores the size of the shape if it is a line or point
};
In my main program I need a vector of type shape. How would I store values into the vector inside of the struct shapes using the the vector of struct shapes.
For instance, vector<shape> myshapes;
If I wanted to store a value into the first index of my verts vector, inside of my first index of my myshapes vector how would I do this?
in pseudo code it would look something like this, with i being the index:
myshapes[i].vector[i] = 4; // but I know this is incorrect
Would this be easier to implement using a STL list instead and if so what would that syntax look like?
Thanks for the help I am new to vectors so any advice would be appreciated.
vector supports the use of the [] operator. The syntax and semantics are very similar to using the [] operator with arrays. See: http://en.cppreference.com/w/cpp/container/vector/operator_at.
As with any struct member, you need to access it by name. myshapes[i].verts[j] = 4;.
The general advice given is to use std::vector as your default container of choice. Naturally if you have specific needs (like adding/removing items in the middle of the container) other containers may have better performance characteristics.
If your vector(s) start out empty, you'll have to add elements to them before you can index into them with operator[]. This is usually done with push_back (to add an existing shape object) or emplace_back (to construct a new shape object directly in the vector).
Given vector<shape> myshapes, you could add some shapes like this:
// add 10 shapes
for (size_t n = 0; n < 10; n++) {
shape s; // creates a new, blank shape object
// initialize the shape's data
s.type = ...;
s.shapeSize = ...;
// etc.
// add verts
s.verts.push_back(1.0f);
s.verts.push_back(2.0f);
s.verts.push_back(3.0f);
// etc.
// add the shape to the vector
myshapes.push_back(std::move(s));
}
(Since we're done with s on that last line, we can use std::move. This allows push_back to move the shape's data into the vector instead of copying it. Look up move semantics for more info.)
Once you have stuff in the vector, you can access elements by index like this:
myshapes[index of shape].verts[index of vertex within that shape]
Using [] with an invalid index or when the vector is empty invokes undefined behavior (don't do it or your program will crash/malfunction).

Can I create an array of different sized vectors in C++?

I am working on a program that assigns the user a parking spot in one of 9 lots arranged in a 3x3 grid. Each lot has a different capacity. I want to use vectors so I can make it shrink according to the amount of spaces left in the specific lot, and I feel it makes sense to hold the vectors in a 3-dimensional array. Is this possible in C++, and if so, how would I go about creating it?
I think you mean two-dimensional array. Yes, you can do that.
vector<class> lots[3][3]; // class is your datatype, and you can do better by making 3 a constant
cout << lots[1][1].size() << endl; // access vector in array
A three dimensional array using vectors is simple. e.g.
#include <vector>
using std;
vector<vector<vector<Node>>> lot; // Where Node is a datatype;
lot[x][y][z] = some value; // To write
a = lot[x][y][z]; // To read

Inserting elements into 2D vector

so I'm creating a class that implements an adjacency list. Currently in my class definition I initialized two vectors:
vector<vector<int>> adjList;
vector<int> neighbors;
and I declared two functions that I plan to use to make it:
bool constructAdjList();
bool insertIntoAdjList(int, int);
It's getting difficult wrapping my head around 2D vectors. I understand that it is essentially a vector of vectors, but I'm confused about how to insert a new value into one of the "subvectors". For example, I am able to create an adjacency list in createAdjList that is empty with the following loop:
for (int i = 0; i < numOfValues; i++){
neighbors.push_back(0);
adjList.push_back(neighbors);
neighbors.clear();
}
But how can I say, push_back the value 5 to the 4th vector in adjList, which would be represented in my insertIntoAdjList function as
insertIntoAdjList(4, 5);
I know I can access a specific value in a 2D vector by saying adjList[4][1], but how can I push one onto it?
Thanks!
To push on the vector that is an element of another vector, you simply do this
adjList[x].push_back();
If initially you do not have any values in the vector -
You can push values into one vector and then push this vector into the 2D vector.
For example:
vector< vector<int> > vt1;
vector<int> vt2;
vt2.push_back(value);
vt1.push_back(vt2);
If your vector is already populated then -
vt1[index].push_back(value);
A couple of notes here.
Your loop can be significantly shortened just be using the constructors of your two members:
vector<int> neighbors(1, 0); // set to length 1, value is zero
vector<vector<int>> adjList(numOfValues,neighbors); // "outer" vector is numOfValues long
. // each row is a *COPY* of neighbor
If you can't do this at construction time (maybe numOfValues isn't known yet), then there's still a better loop phrasing we can use:
// neighbors object can be reused
neighbors.clear(0);
neighbors.push_back(0);
adjList.reserve(numOfValues); // reserving memory ahead of time will prevent allocations
for (int i = 0; i < numOfValues; i++){
adjList.push_back(neighbors); // push_back is by *COPY*
}
In your example, by using clear and push_back to essentially build the same vector every loop iteration, you are risking an allocation and deallocation each iteration. In practice, most implementations won't do this, but if we can both shorten and potentially make things more efficient, we may as well.
Lastly, if the number of neighbors is relatively small and similar row to row (for instance a finite elements code with tetrahedral elements, where each element connects to ~5 others), then as others have suggested you may be better off with a different structure than vector-of-vector. For instance, a single vector that is logically organized such that a new "row" begins every N elements.

Vector of Vectors Containing Structs

I have defined a struct
struct path{
char type;
bool visit;
bool inPath;
int level;
}
I have also defined a vector of vectors of this type struct
vector < vector<path> > spaceStation(numLevels*levelSize,vector<path> (levelSize));
I have two questions.
1) Have i defined the vector so that the number of rows pertain to (numLevels*levelSize) and columns pertain to levelSize
2) When accessing the individual elements of the vector, how can i set the elements of the struct inside it. I have tried using the .at() member function to little success
Re: 1
Yes. But I can't help feeling like you wanted to do this instead:
vector < vector<path> > spaceStation(numLevels,vector<path> (levelSize))
Note that using the term "rows" and "columns" is entirely in your imagination, concerning vectors. You just have a vector inside another vector. It's like an array of arrays - no special geometry implied.
Re: 2
Because you have a vector of vector, you need to use two indices, not just one:
spaceStation[level][pathindex].visit = true;
Where spaceStation[level] returns the vector at index level, which you then take the element at position pathindex (which is an instance of your struct), and finally modify a value in that struct.
For Q1, you are correct.
For example: a 4x4 dimension vector.
vector< vector< int > > vec(4, vector(4));
For Q2, to access the path, can't you do the following:
spaceStation[2][3] to access row 2 column 3 data, for example.
Then you can do:
spaceStation[2][3].visit to access elements inside your struct.