2D Vectors/Dynamic Arrays - c++

I'm trying to work with 2D arrays in order to keep track of some objects that are laid out in a grid fashion. I would like each element of the of the 2d array to contain an Object*. Object being a class I have defined. However working with these things isn't exactly easy.
This is the my method for filling the 2D array with Object pointers:
int xDim;
//how far to go in the x direction
//x's Dimension that is
Object *** test; //the highest level pointer used
test = new Object ** [xDim];
//add horizontal array of Object **
for(int fillPos=0; fillPos < xDim; fillPos++){
//point each Object ** to a new Object * array
//add column arrays
test[fillPos] = new Object*[zDim];
}
My intention is then to use this array's Object pointers to point to the child class of Object, say childObj. My intent is to use them in this way.
for (int xPos=0; xPos < xDim; xPos++){
for(int zPos=0; zPos < zDim; zPos++){
//pointing each Object * in the 2D array to
//a new childObj
test[xPos] [zPos] = new childObj;
}
}
I realize this could potentially be a real hassle in terms of memory. I'm asking if this is a nice way to handle such a situation. Could perhaps something like
vector< <vector<Object*> > work better? Would vectors manage the deletion nicely so as to avoid memory leaks? Or perhaps I would simply have to loop through the vector and call delete on each Object* before getting rid of the vectors themselves?
So, should I use arrays as I have or vectors? What could be some problems associated with each method?

Using Object *** requires that you go through and delete each Object Pointer, each Array of Object Pointers, and then the finally delete the outermost Array of Object**, in that order. In my opinion this leaves a lot of room for carelessness and mistakes.
for (int xPos=0; xPos < xDim; xPos++) {
for (int zPos=0; zPos < zDim; zPos++) {
delete test[xPos][yPos]; // delete the object ptr
}
delete[] test[xPos]; // delete each array of object ptr
}
delete[] test; // delete the array of array of object ptrs
I would much rather prefer the vector approach, because the vectors are locally scoped. Dynamic allocation can be rather expensive and should be avoided if possible.
So for the vector approach, you would only need to delete the Object ptrs. (A good rule of thumb is that every call to new requires a corresponding call to delete).
vector<vector<Object*>> matrix;
... // some code here
for each (vector<Object*> vec in matrix)
for each (Object* oPtr in vec)
delete oPtr;
If you knew the size of your 2-D array at compile-time, you could achieve the same effect of avoiding memory management for the 2-D array, and simply manage the Object pointers.
Object * matrix[xDim][yDim]; // xDim and yDim are compile-time constants
But I still like vectors because they have the added benefit of being able to resize themselves dynamically unlike arrays, so you won't have to worry about knowing the size upfront.

Related

When should I use delete? (Consequences of not deleting after a dynamically created 2d array)

I am new to dynamic allocation and pointers. I will try to fill out a 2D dynamic array from a file and then apply a maze-solving algorithm (wall follower)on it.
Assuming I create a dynamically allocated 2D array like this:
int** board;
board = new int* [rowsize];
for(int row = 0; row < rowsize; row++)
{
board[row] = new int[colsize];
}
If I know that I won't be using this pointer for another variable, can I get away with not using delete for board ? If not what could potentially go wrong (If you are familiar with the wall follower algorithm) ? Also how do I delete a pointer to a pointer, would delete board be sufficient?
can I get away with not using delete for board?
Yes, but not for very long: repeated failure to delete arrays that your program allocates is a memory leak that eventually runs your process out of memory.
how do I delete a pointer to a pointer, would delete board be sufficient?
No, you will need to delete each pointer that you allocated and stored inside board:
for(int row = 0; row < rowsize; row++) {
delete[] board[row];
}
delete[] board;
Note square brackets after delete to indicate that you deleting an array, they are very important.
Allocating an deallocating memory for a rectangular matrix is a solved problem in C++ library. Switch to using a vector of vectors to avoid dynamic resource allocations:
std::vector<std::vector<int>> board(rowsize, std::vector<int>(colsize, 0));
If you don't delete the arrays you allocated they will continue to consume memory until the program is terminated. This might not technically be wrong, but it is wasteful.
With regard to deleting the board - no, it is not enough. You should delete every pointer you allocate with new:
for(int row = 0; row < rowsize; row++)
{
delete[] board[row];
}
delete[] board;
What you need to delete is the memory you allocated with new. That means that you don't deallocate the pointer itself, but the heap's memory it is pointing at.
So, you only need to do delete[] board. This will free up the int* array. It is not strictly necessary to use [] in this case, since it is a fundamental type array, but it is good practice to use it always for arrays, so you won't mess up when it's not like that.
Calling delete[] on an array will call the destructors of all objects inside the array itself, as well as freeing up the array. It is not necessary however for fundamental types.
Also note that you don't need to free the int** board. The pointer are variables like any other with some special capability, but they are allocated in the stack just like any other when you declare them like that.
Hope it helps :)

How to init a double**?

I need to init/use a double ** (decleared in my header):
double **pSamples;
allocating (during the time) a matrix of NxM, where N and M are get from two function:
const unsigned int N = myObect.GetN();
const unsigned int M = myObect.GetM();
For what I learnt from heap and dynamic allocation, I need keyword new, or use STL vector, which will manage automatically allocate/free within the heap.
So I tried with this code:
vector<double> samplesContainer(M);
*pSamples[N] = { samplesContainer.data() };
but it still says I need a constant value? How would you allocate/manage (during the time) this matrix?
The old fashioned way of initializing a pointer to a pointer, is correctly enough with the new operator, you would first initialize the the first array which is a pointer to doubles (double*), then you would iterate through that allocating the next pointer to doubles (double*).
double** pSamples = new double*[N];
for (int i = 0; i < N; ++i) {
pSambles[i] = new double[M];
}
The first new allocates an array of double pointers, each pointer is then assigned to the array of pointers allocated by the second new.
That is the old way of doing it, remember to release the memory again at some point using the delete [] operator. However C++ provide a lot better management of sequential memory, such as a vector which you can use as either a vector of vectors, or simply a single vector capable of holding the entire buffer.
If you go the vector of vector way, then you have a declaration like this:
vector<vector<double>> samples;
And you will be able to reference the elements using the .at function as such: samples.at(2).at(0) or using the array operator: samples[2][0].
Alternatively you could create a single vector with enough storage to hold the multidimensional array by simply sizing it to be N * M elements large. However this method is difficult to resize, and honestly you could have done that with new as well: new double[N * M], however this would give you a double* and not a double**.
Use RAII for resource management:
std::vector<std::vector<double>> samplesContainer(M, std::vector<double>(N));
then for compatibility
std::vector<double*> ptrs(M);
for (std::size_t i = 0; i != M; ++i) {
ptrs[i] = samplesContainer[i].data();
}
And so pass ptrs.data() for double**.
samplesContainer.data() returns double*, bur expression *pSamples[N] is of type double, not double*. I think you wanted pSamples[N].
pSamples[N] = samplesContainer.data();

Which would be better: A unique_ptr to a 2D array or a 2D array of unique_ptrs?

I'm currently in the middle of making an old project of mine memory-safe.
In this project I have a 2D array populated with pointers to instances of my own class Block.
declared like so:
Block* gemGrid[xMax][yMax];
and populated later like so:
for(int i = 0; i<8; i++)
{
for(int j = 0; j<8; j++)
{
//do stuff here
gemGrid[i][j] = new Block(i,j, gridOffset);
}
}
This works fine.
I had the idea of creating a 2D array of unique_ptr<Block> instead of Block*.
Which i decided to declare like so:
unique_ptr<Block> gemGrid[xMax][yMax];
and populate like so:
for(int i = 0; i<8; i++)
{
for(int j = 0; j<8; j++)
{
gemGrid[i][j].reset( new Block(i,j, gridOffset));
}
}
However when I try this the compiler decides to completely ignore the second for loop (the 'j' incremented section), and create only a one dimensional array.
Which leads me to ask, does C++ have a problem with unique_ptrs in 2D arrays? And should I just stick with a 2D array of pointers to Blocks, and have one unique_ptr make sure this array is killed-of when it goes out of scope?
C++ has no objection whatever to a 2-D array of unique_ptr.
The two alternatives you offer don't seem like real alternatives to me. If you have a unique_ptr to a 2-D array of Block*, and you allocate xMax * yMax instances of Block using new and store pointers to them in your array, then who or what is going to free those instances of Block? Certainly the unique_ptr is not. So the answer to "should I just do that" is almost certainly "no", because you'll have memory leaks.
The most "obvious" way to allocate a 2-D layout of instances of Block is to define a 2-D array of Block (either using a builtin array or std::array if available). If you can identify anything about that that doesn't suit you, then someone can suggest an alternative way for your old code to avoid memory leaks.
[In response to a comment above] Having done Block gemGrid[xMax][yMax];, you can get a pointer to one of your Block objects, if you need one, like this: &gemGrid[i][j]. Needing a pointer has absolutely nothing to do with memory allocation. Pointers are the means by which new lets you access the objects it allocates, but you can take a pointer to an object regardless of how it is allocated.

Vector of vector pointer memory allocation

First I want to say that, I have a vector which has thousand of vectors inside. Each of these inside vectors has thousand of numbers inside. I want to keep memory management safe and memory usage at minimum as much as possible.
I want to ask that if I have a code similiar to below
int size = 10;
vector<vector<double>>* something = new vector<vector<double>>(size);
vector<double>* insideOfSomething;
for(int i = 0; i < size; i++){
insideOfSomething = &(something->at(i));
//...
//do something with insideOfSomething
//...
}
I know that 'something' will be created in heap. What I don't understand is where the vectors are placed, 'insideOfSomething' points? If they are created in stack, then this means that I have a vector pointer, which points a vector in heap, that has vectors inside which are created in stack? (I'm very confused right now.)
If I have a code similiar to the one below;
vector<vector<double>*>* something = new vector<vector<double>*>(size);
vector<double>* insideOfSomething;
for(int i = 0; i < size; i++){
something->at(i) = new vector<double>();
insideOfSomething = something->at(i);
//...
//do something with inside insideOfSomething
//...
}
right know all of my vectors are stored in heap, right?
Which one is more usefull according to the memory management?
You should avoid allocating vectors on the heap and just declare them on the stack since the vector will manage its objects on the heap for you. Anywhere you want to avoid creating a copy you can just use a reference or const reference (which ever is necessary).
vector<vector<double> > something(size);
for(int i = 0; i < size; i++)
{
vector<double> &insideOfSomething = something.at(i);
//use insideOfSomething
}
Let's take a random, simplistic implementation of vector, as I think this will help you.
template <class T, class Alloc>
class vector
{
private:
T* buffer;
std::size_t vector_size;
std::size_t vector_capacity
Alloc alloc;
public:
...
};
In this case, if we write:
vector<int> v;
v.push_back(123);
... the pointer, buffer, the integrals: vector_size and vector_capacity, and the allocator object, alloc, will all be created on the stack (along with allocating any additional memory necessary for structure padding and alignment).
However, vector itself will allocate memory on the heap to which this buffer pointer will store its base address. That will always be on the heap and will contain the actual contents of the vector as we think of them.
This is still more efficient than this:
vector<int>* v = new vector<int>;
v->push_back(123);
...
delete v;
... as this would involve a heap allocation/deallocation for the vector itself (including its data members) in addition to the memory vector itself allocates for its internal contents (the buffer). It also introduces an additional level of indirection.
Now if we have a vector of Somethings (vector of vector or anything else):
vector<Something> v;
Those Something instances are always going to be allocated within a contiguous heap buffer since they would reside in the dynamically allocated memory blocks that vector creates and destroys internally.
In vector<> all data stored in heap
And i think you should simply use
vector< vector<double> > something;
I want to keep memory management safe and memory usage at minimum as much as possible.
Then
vector<vector<double>>* something = new vector<vector<double>>(size);
is already not good. As said in the other answers, vector already has its data on the heap, no need to mess around with new to achieve this. In fact, the objects' location is like
S t a c k H e a p
(vector<double>) sthng[0]
(vector<vector<double>>) sthng (vector<double>) sthng[1]
...
- - - - - -
(double) sthng[0][0]
(double) sthng[0][1]
...
- - - - - -
(double) sthng[1][0]
(double) sthng[1][1]
...
(of course, there is no particular ordering of the blocks on the heap)
Joe and hired777's answers explain that a vector will be allocated on the heap no matter what. I'll try to give some insight on the reason for this.
A vector is a resizeable container. Generally it doubles in size when it reaches capacity which means it needs to be able to allocate more memory than it had already allocated. Hence even when you declare vector inside a function and hence on the stack, internally it's holding a pointer to it's data on the heap and on going out of the function's scope, it's destructor will delete this data from the heap.

How to reference objects in a 2 dimensional array?

I read that you can declare an aray of objects by this line
Enemy * d = new Enemy[2];
but when i tried to make a 2 dimensional array, there was an error where this cant be initialized. I also tried this
Enemy *enemies[6][2];
but i am not sure how to reference to each object in that array and and how to pass that reference to a function.
You need to use a pointer to a pointer in order to make a jagged array.
Enemy** d = new Enemy*[6];
for (size_t i = 0; i < 6; ++i)
d[i] = new Enemy[2];
If you plan on making a fixed size array, you can just create it the same as you would a normal array.
Enemy enemies[6][2];
You then just reference them using two indices.
enemies[2][1].roar();
Note: You will find that multi-dimensional arrays tend to lead to more headaches than they are worth. It is much cleaner to maintain a single dimension array and simply index it based on the number of rows and columns.
Enemy* enemies = new Enemy[rows * cols];
Enemy* getEnemy(size_t row, size_t col)
{
return enemies + (row * cols + col);
}
If you really want to allocate a 2D array on the heap, this is how you do it:
Enemy (*enemies)[2] = new Enemy[6][2];
But it's a lot simpler without the indirection:
Enemy enemies[6][2];
For C++ you should use std::vectors instead of C Arrays.
std::vector<std::vector<Enemy> > d(6);
for (size_t i = 0; i < 6; ++i)
d[i].resize(2);
//now d is ready to use
d[1][2];
You'd do
Enemy (*enemies)[2] = new Enemy[6][2];
That is, a pointer to arrays of 2 enemies.
Note that only the first array level can be made a pointer and therefore determined at run time.
Also note that your second definition creates an array of 6*2 pointers to enemies. Assuming you've initialized them all, you'd access them as *enemies[j][k], or if each pointer itself points to an array, as enemies[j][k][l].
Note that if you want to have both indices determined at run time, you should allocate one big array and use index arithmetics:
Enemy* enemies = new Enemy[6*2];
// access the element (j,k)
enemy[6*j+k].fight();
Of course, generally it is better to use a vector<Enemy> unless your class Enemy is not suitable for a vector, e.g. because it cannot be copied (resp. in C++11, moved). Also, when doing multidimensional arrays that way, ideally you should encapsulate the array and index logic in a class.