Dynamically allocating a 2D array of object pointers in a class - c++

I'm struggling at the moment with the idea of dynamically allocating arrays at runtime. Coming from Java, used to just declaring the arrays in the class skeleton and only needing the size in the implementation.
This is what I've found to dynamically allocate 2D arrays:
Grid.h
Block** grid;
Grid.cpp
grid = new Block*[size]
for(int i = 0 ; i < size ; i++)
grid[i] = new Block[size]
This works pretty okay, although dealing with objects I've always been told that using pointers to objects rather than storing the objects themselves is much better performance wise. So when I tried to make the second dimension of arrays pointers like this:
Grid.cpp
grid = new Block*[size]
for(int i = 0 ; i < size ; i++)
grid[i] = new Block*[size];
When I changed my code to this, I got an error:
error: assigning to 'Block *' from incompatible type 'Block **'; dereference with *
grid[i] = new Block* [size];
^ ~~~~~~~~~~~~~~~~~
*
Being slightly new to the C++ ways of doing things, can someone tell me what I'm doing wrong? Or even if I'm trying to do the wrong thing entirely?
Thanks in advance!

I would not recommend you writing this type of code, but if you still want to hack your way out you can do something like this:-
int main()
{
Block*** grid;
grid = new Block**[10];
for(int i = 0 ; i < 10 ; i++)
{
grid[i] = new Block*[10];
}
/*Here, we have created a grid of pointers*/
/*
|Block**[10]|
|Block[0] **|------------->|Block* [10]|
|Block[1] **|------------->|Block* [10]|
|Block[2] **|------------->|Block* [10]|
|Block[3] **|------------->|Block* [10]|
..
..
|Block[9] **|------------->|Block* [10]|
*/
for(int i = 0 ; i < 10 ; i++)
{
for(int j = 0 ; j < 10 ; j++)
{
grid[i][j] = new Block[10];
}
}
/*
|Block**[10]|
|Block[0] **|------------->|Block* [0]|------------->|Block1|Block2| .. |Block10|
|Block* [1]|------------->|Block1|Block2| .. |Block10|
|Block* [2]|------------->|Block1|Block2| .. |Block10|
..
|Block* [9]|------------->|Block1|Block2| .. |Block10|
|Block[1] **|------------->|Block* [0]|------------->|Block1|Block2| .. |Block10|
|Block* [1]|------------->|Block1|Block2| .. |Block10|
|Block* [2]|------------->|Block1|Block2| .. |Block10|
..
|Block* [9]|------------->|Block1|Block2| .. |Block10|
|Block[2] **|
|Block[3] **|
..
..
|Block[9] **|
*/
}

A dynamic 2D array is an array of pointers to arrays.
You should initialize first the array of pointer, then the others array using a loop.
Here an example using int that creates an array[rowCount][colCount]:
int** array = new int*[rowCount];
for(int i = 0; i < rowCount; ++i)
array[i] = new int[colCount];
otherwise of course you can always have a 2D array on the stack by using:
int array[rowCount][colCount];

Use a linear representation of 2d array:
std::unique_ptr<int[]> array(new int[rowCount*colCount]);
for (size_t r = 0; r < rowCount; r++)
for (size_t c = 0; c < colCount; c++)
(array.get())[r*colCount + c] = r*c;

Alocating array of pointers can also be done in thread safe manner:
size_t allocatedRows = rowCount;
try{
array = new char*[allocatedRows];
while(allocatedRows){
--allocatedRows;
array[allocatedRows] = new char[colCount];
}
}catch(std::bad_alloc& ex){
while(++allocatedRows < lines)
delete array[allocatedRows];
delete array;
throw;
}
Two thing to note in code above:
1) allocatedRows is not decremented in [] operator, as behaviour would be undefined
2) After allocating array of pointers, dereferencing array elemnts has undefined behaviour(just like normal pointer without assignment).
Please also keep in mind that in case above I didn't recovered from bad_alloc I just rethrowed, It can be logged somewhere else before call to termination. If You would like to create array of pointers from other user defined objects You could use std::uninitialized_copy or std::uninitialized_fill.
Another way would be just to use vectors.

Related

c++ How to deallocate and delete a 2D array of pointers to objects

In SO question [How to allocate a 2D array of pointers in C++] [1], the accepted answer also makes note of the correct procedure of how to de-allocate and delete said array, namely "Be careful to delete the contained pointers, the row arrays, and the column array all separately and in the correct order." So, I've been successfully using this 2D array in a cellular automaton simulation program. I cannot, however, get this array's memory management correct. I do not see an SO answer for how to do this other than the reference above.
I allocate the 2D array as follows:
Object*** matrix_0 = new Object**[rows];
for (int i = 0; i < rows; i++) {
matrix_0[i] = new Object*[cols];
}
My futile attempt(s) (according to Valgrind) to properly de-allocate the above array are as follows:
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix_0[i][j] = NULL;
}
}
delete [] matrix_0;
matrix_0 = NULL;
Clearly, I'm missing the rows and cols part as reference [1] suggests. Can you show me what I'm missing? Thanks in advance.
[1]: (20 Nov 2009) How to allocate a 2D array of pointers in C++
You have a tonne of deleting to do in this:
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
delete matrix_0[i][j]; // delete stored pointer
}
delete[] matrix_0[i]; // delete sub array
}
delete [] matrix_0; //delete outer array
matrix_0 = NULL;
There is no need to NULL anything except matrix_0 because they are gone after delete.
This is horrible and unnecessary. Use a std::vector and seriously reconsider the pointer to the contained object.
std::vector<std::vector<Object*>> matrix_0(rows, std::vector<Object*>(cols));
Gets what you want and reduces the delete work to
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
delete matrix_0[i][j]; // delete stored pointer
}
}
But SergeyA's suggestion of storing unique_ptr, std::vector<std::vector<std::unique_ptr<Object>>> matrix_0; reduces the deletions required to 0.
Since speed is one of OP's goals, there is one more improvement:
std::vector<std::unique_ptr<Object>> matrix_0(rows * cols);
Access is
matrix_0[row * cols + col];
This trades a bit of visible math for the invisible math and pointer dereferences currently going on behind the scenes. The important part is the vector is now stored as a nice contiguous block of memory increasing spacial locality and reducing the number of cache misses. It can't help with the misses that will result from the pointers to Objects being scattered throughout memory, but you can't always win.
A note on vector vs array. Once a vector has been built, and in this case it's all done in one shot here:
std::vector<std::unique_ptr<Object>> matrix_0(rows * cols);
all a vector is is a pointer to an and a couple other pointers to mark end and the the location of the last location used. Access to the data array is no different from access to a dynamic array made with new. Using the index operator [] compiles down to data_pointer + index exactly the same as using [] on an array. There is no synchronizing or the like as in Java's Vector. It is just plain raw math.
Compared to a dynamic array all a preallocated vector costs you is two pointers worth of memory and in return you get as close to no memory management woes as you are likely to ever see.
Before setting the pointers to NULL, you should delete them first. After every pointer in the column are deleted, you can delete[] the row and set it to NULL, as every element is deleted and gone.

Pointer to 3D Arrays of Pointer

I'm trying to create a Pointer to a dynamic 3D Array full of Pointers. I'm working with Voxel, so let's say that t_cube is my object.
First, I tried doing this:
t_cube* (*m_Array)[][][];
I thought I could do like
m_Array = new t_cube[sizeX][sizeZ][sizeY];
Compiling this failed, however.
Next I tried this:
t_cube *(m_Model[]); // This is my .h
{
t_cube *model_Tempo[sizeX][sizeZ][sizeY]; // And this is in my class constructor.
m_Model = model_Tempo;
}
Again, this failed to compile.
I hope this example would be helpful to solve your problem:
Since, we are dealing with Pointer of 3-D Array. So, if I write it in C++ grammar, it would be like:
t_cube *array[x_size][y_size][z_size];
But, you already mentioned, it fails to execute.
Now, do the same thing using Dynamic Allocation Approach.
t_cube ****array; // Since, it a pointer to the 3D Array
array = new t_cube ***[x_size];
for(int i=0; i<x_size; i++) {
array[i] = new t_cube **[y_size];
for(int j =0; j<y_size; j++) {
array[i][j] = new t_cube *[z_size];
}
} /* I'm sure this will work */
And, the reasons you were facing trouble:
The size of the m_Array could be very large : x_size * y_size * z_size * sizeof(t_cube) .
You must have defined m_Array locally (inside the function), which is the major reason of program malfunction.

Trying to fill a 2d array of structures in C++

As above, I'm trying to create and then fill an array of structures with some starting data to then write to/read from.
I'm still writing the cache simulator as per my previous question:
Any way to get rid of the null character at the end of an istream get?
Here's how I'm making the array:
struct cacheline
{
string data;
string tag;
bool valid;
bool dirty;
};
cacheline **AllocateDynamicArray( int nRows, int nCols)
{
cacheline **dynamicArray;
dynamicArray = new cacheline*[nRows];
for( int i = 0 ; i < nRows ; i++ )
dynamicArray[i] = new cacheline [nCols];
return dynamicArray;
}
I'm calling this from main:
cacheline **cache = AllocateDynamicArray(nooflines,noofways);
It seems to create the array ok, but when I try to fill it I get memory errors, here's how I'm trying to do it:
int fillcache(cacheline **cache, int cachesize, int cachelinelength, int ways)
{
for (int j = 0; j < ways; j++)
{
for (int i = 0; i < cachesize/(cachelinelength*4); i++)
{
cache[i][ways].data = "EMPTY";
cache[i][ways].tag = "";
cache[i][ways].valid = 0;
cache[i][ways].dirty = 0;
}
}
return(1);
}
Calling it with:
fillcache(cache, cachesize, cachelinelength, noofways);
Now, this is the first time I've really tried to use dynamic arrays, so it's entirely possible I'm doing that completely wrong, let alone when trying to make it 2d, any ideas would be greatly appreciated :)
Also, is there an easier way to do write to/read from the array? At the moment (I think) I'm having to pass lots of variables to and from functions, including the array (or a pointer to the array?) each time which doesn't seem efficient?
Something else I'm unsure of, when I pass the array (pointer?) and edit the array, when I go back out of the function, will the array still be edited?
Thanks
Edit:
Just noticed a monumentally stupid error, it should ofcourse be:
cache[i][j].data = "EMPTY";
You should find your happiness. You just need the time to check it out (:
The way to happiness

Resizable Array with pointers

My program works but my professor says that my code is incorrect but stated that he will get to why in the fall term... What is he talking about?
perhaps something is improper? Even if you are incorrect I would appreciate picking your brain :)
void CResizableArray::SetSize( int intNewSize )
{
int intIndex = 0;
if( intNewSize < 0 ) intNewSize = 0;
if( intNewSize > intMAXIMUM_ARRAY_SIZE )
{
intNewSize = intMAXIMUM_ARRAY_SIZE;
}
//////////////////////////////////////
// ---> HUGE BUG HERE <--- //
// Code works but is WRONG //
// WHY IS THIS HELP ME FIND THE BUG //
//////////////////////////////////////
m_intArraySize = intNewSize;
m_paintValues = new int [m_intArraySize];
// Initialize to zero
for( intIndex = 0; intIndex < m_intArraySize; intIndex++ )
{
*( m_paintValues + intIndex ) = 0;
}
}
Presumably before this line
m_paintValues = new int [m_intArraySize];
m_paintValues pointed to another array. That array has now been leaked -- you don't have a pointer to it, so it can never be freed. That memory can therefore never be reused. Write a program that does a lot of this, and it'll run out of memory before running very long.
When you're through with a block of memory, you need to free it. Here, the proper thing to do might look something like
delete[] m_paintValues;
m_paintValues = new int [m_intArraySize];
There are more issues, though. First of all, you can never use delete[] unless you know that m_paintValues definitely points to an array; you could ensure that in the constructor. More troubling is that fact that when you set a new size, any data previously in m_paintValues is discarded -- don't you want to copy the old values into the new array? Doing so would mean using a temporary variable to hold the new array when first allocated, copying the data, and then assigning the new array to the member variable.
He may mean that since it is a resize you should keep the old contents of the array and transfer them over to the new array, in your snippet you just throw away the old content creating a new empty array.
so instead of
m_paintValues = new int [m_intArraySize];
// Initialize to zero
for( intIndex = 0; intIndex < m_intArraySize; intIndex++ )
{
*( m_paintValues + intIndex ) = 0;
}
do
int* newBiggerArray = new int[m_intArraySize];
for (intIndex = 0; intIndex < m_intArraySize; ++intSize)
{
if ( intIndex < oldMaxSize )
{
newBiggerArray[intIndex] = m_paintValues[intIndex];
}
else
{
newBiggerArray[intIndex] = 0;
}
}
delete [] m_paintValues;
m_paintValues = newBiggerArray;
I will leave the part to handle a resize to a smaller value than previous for you to figure out.

initializing a multi dimensional array c++

I am working in VC++ 2008, and am trying to allocate a multi-dimensional array of chars to do some file work. I know that whenever an array is allocated all the members of the array should be initialized usually in a successive order. what I have currently is this.
char ** thing = new char *[lineY];
for (int ii = 0; ii < lineY; ii++){
thing[ii] = new char[lineX];
}
... // working with array
// deleting each part of the array.
for (int ii = 0; ii < lineY; ii++){
delete [] thing[ii];
}
delete [] thing;
the problem that I am running into is that if I add the array to the watch list, or put a break right after its been allocated the debugger states that the array is equal to a number like 51, or 32, and not a block of space with indexes, and values, but when I try to initialize the values of each index by making my allocation this:
char ** thing = new char *[lineY];
for (int ii = 0; ii < lineY; ii++){
thing[ii] = new char[lineX];
for (int jj = 0; jj < lineX; jj++){
thing[ii][jj] = '';
}
}
edit: the compiler throws "C2137 empty character constant" am I doing something wrong?
edit: read msdn on the error number, and found answer
You cannot write thing[ii][jj] = '' because '' is an empty character constant which isn't allowed. Try replacing '' with something like ' ' (with the space between 's)
Are lineX and lineY compile-time constants? In that case:
std::array<std::array<char, lineX>, lineY> thing;
Otherwise:
std::vector<std::vector<char> > thing(lineY, std::vector<char>(lineX));