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

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.

Related

C++ deleting array on the heap

I'm having difficulty finding an answer on how to specifically perform this operation properly.
I'd like to better understand different ways to delete new memory allocated on the heap, especially in the instance of a two-D array.
For my example:
I have an array of size 5 on the stack consisting of int pointers (int *d[5]).
I initialize each of these int pointers in a loop to create and point to an int array of size 8 on the heap (d[i] = new int[8]).
I have now essentially created a two-D array (d[j][k]).
My question is what is the syntax for deleting only the individual arrays (int[8]) on the heap?
I currently have it as this, but when debugging it appears the arrays are not deallocated after it is performed...
for(int i = 0; i < 5; ++i)
delete d[i];
Should it be "delete [] d[i]" or just "delete [] d" or some other variation? Also, is there a way to delete the individual elements of the int[8] arrays? If anyone could concisely explain the syntax and their differences that would be super helpful. Thank you!
If you allocated arrays via d[i] = new int[8], then you must delete them via delete[] d[i]. There's no way to deallocate individual elements of such an array without deallocating the whole thing.
you mentioned that you are allocating the inner arrays within a loop. which I believe it looks something like this.
int*d[2];
for (int i = 0; i < 2; i++)
{
d[i] = new int[3];
}
Notice that d[2] contains just pointers to the arrays.
so in order to delete this array, you have to iterate through each set of array pointers
and call delete[] d[i];
for (int i = 0; i < 2; i++)
{
delete[] d[i];
}
As an additional note, it would be very advantageous to know how your IDE tries to detect memory corruptions.
for example in the visual studio (In DEBUG mode)
0xCD means Allocated memory via malloc or new but never written by
the application.
0xCC means uninitialised variables.
0XDD means memory has been released with delete or free.
0xFD means fence memory and acts as a guard. used for detecting indexing arrays that go out of bounds.
with that in mind lets see if we can make sense of what the IDE is doing when the above code is executed.
When the d array is declared int*d[2]; the memory layout looks like the following;
notice that d array has two elements but none of those have initial values so they are assigned to the 0xCC
lets see what happens after we do d[i] = new int[3];
notice that d array now has two elements each element contains an int array. the values you see are the address of the pointers to the array we allocated the memory for.
since we know what the addresses are we can look into the memory and see whats happening in there when allocating and deleting the each array.
for example after we allocate our second int array within the for loop, the memory location would look something like this;
notice that all the array element has 0xCD with ending of 0xFD.This would indicate in my IDE that the memory allocated and has a fence guards around it.
lets see what happens when the d[2] is deleted.

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 :)

access violation in deleting a 2d array

I have a 2d array of object pointers, and I am trying to write a deallocator for an object that to delete both the pointers in the array, and then delete the array itself. I define the array in the header of the object to be destructed like so
space* board[6][6];
I allocate the space objects in the array like so:
board[0][0]= new space(1,0);
board[0][1] = new space(1, 0);
board[0][2] = new space(1, 0);
My current destructor is like this
for (int i = 0; i < 6; ++i)
{
for (int j = 0; j < 6; ++j){
delete board[i][j];
}
delete[] board[i];
}
delete[] board;
When I do this, I get this message: Unhandled exception at 0x5080A9E8 (msvcr120d.dll) in Blitz.exe: 0xC0000005: Access violation reading location 0xFEEEFEE2.
I'm not quite sure what to do, I've tried looking around, and it seems like my destructor should be okay. I know if I had a decent programming education, I would use something better, like a vector or something else. I downloaded a pdf on how people actually use C++ these days, and I'll probably go over that soon, but I would just rather just take care of this memory leak and move on.
The board and board[i] variables should not be deleted because they have not been allocated by new.
You are mixing new with delete[]. The behaviour of your program is therefore undefined.
It would be marginally better if you used std::vector<std::vector<space>> instead. Then, the memory management would be done for you.
But if you're modelling a matrix then this is also not a good choice: it will have a "jagged edge" and the memory allocated is not contiguous.
A good alternative would be to allocate a contiguous block and use the convention (i * rows + j) for the element at (i, j). A std::vector<space> would suffice. Then consider using a 3rd party matrix library like BLAS (www.boost.org).

Return 2d array from C++

Inside a function, I make a 2d array that fills itself from a text file and needs to get returned to main. The array stays a constant size through the whole program.
I know this is something that gets asked a lot, but I always seem to get one of two answers:
Use std::vector or std::array or some other STD function. I don't really understand how these work, is there any site actually explaining them and how they act compared to normal arrays? Are there any special #includes that I need?
Or
Use a pointer to the array, and return the pointer. First, on some of the answers to this it apparently doesn't work because of local arrays. How do I tell when it does and doesn't work? How do I use this array back in the main function?
I'm having more trouble with the concept of pointers and std::things than with the actual code, so if there's a website you know explains it particularly well, feel free to just put that.
Not necessarily the best solution, but the easiest way to get it working with vectors. The advantages are that you don't need to delete memory (happens automatically) and the array is bounds-checked in debug mode on most compilers.
#include <vector>
#include <iostream>
using array2D = std::vector< std::vector< int > >;
array2D MyFunc(int x_size, int y_size)
{
array2D array(y_size, vector< int >(x_size));
int i = 0;
for (int y = 0; y < array.size(); y++)
{
for (int x = 0; x < array[y].size(); x++)
{
// note the order of the index
array[y][x] = i++;
}
}
return array;
}
int main()
{
array2D bob = MyFunc(10, 5);
for (int y = 0; y < bob.size(); y++)
{
for (int x = 0; x < bob[y].size(); x++)
{
cout << bob[y][x] << "\n";
}
}
}
Live example:
http://ideone.com/K4ilfX
Sounds like you are new to C++. If this is indeed the case, I would suggest using arrays for now because you probably won't be using any of the stuff that STL containers give you. Now, let's talk about pointers.
You are correct that if you declare a local array in your function, the main function won't have access to it. However, this is not the case if you dynamically allocate the array using the new keyword. When you use new to allocate your array, you essentially tell the compiler to reserve a chunk of memory for your program. You can then access it using a pointer, which is really just the address of that chunk of memory you reserved. Therefore, instead of passing the entire array to the main function, all you need to do is pass a pointer (address) to that array.
Here are some relevant explanations. I will add to them as I find more:
Dynamic Memory
The easiest way to create a 2d array is as follows:
char (*array)[10];
array = new array[5][10];
Two dimensional arrays can be tricky to declare. The parenthesis above in the variable declaration are important to tell the compiler array is a pointer to an array of 10 characters.
It is really essential to understand pointers with C and C++ unless using the std:: collections. Even then, pointers are widely prevalent, and incorrect use can be devastating to a program.

2D Vectors/Dynamic Arrays

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.