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.
Related
I have the following piece of code, which is only half on the entire code:
// Declare map elements using an enumeration
enum entity_labels {
EMPTY = 0,
WALL
};
typedef entity_labels ENTITY;
// Define an array of ASCII codes to use for visualising the map
const int TOKEN[2] = {
32, // EMPTY
178 // WALL
};
// create type aliases for console and map array buffers
using GUI_BUFFER = CHAR_INFO[MAP_HEIGHT][MAP_WIDTH];
using MAP_BUFFER = ENTITY[MAP_HEIGHT][MAP_WIDTH];
//Declare application subroutines
void InitConsole(unsigned int, unsigned int);
void ClearConsole(HANDLE hStdOut);
WORD GetKey();
void DrawMap(MAP_BUFFER & rMap);
/**************************************************************************
* Initialise the standard output console
*/
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hStdOut != INVALID_HANDLE_VALUE)
{
ClearConsole(hStdOut);
// Set window title
SetConsoleTitle(TEXT("Tile Map Demo"));
// Set window size
SMALL_RECT srWindowRect;
srWindowRect.Left = 0;
srWindowRect.Top = 0;
srWindowRect.Bottom = srWindowRect.Top + MAP_HEIGHT;
srWindowRect.Right = srWindowRect.Left + MAP_WIDTH;
SetConsoleWindowInfo(hStdOut, true, &srWindowRect);
// Set screen buffer size
COORD cWindowSize = { MAP_WIDTH, MAP_HEIGHT };
SetConsoleScreenBufferSize(hStdOut, cWindowSize);
}
/*************************************************************************/
/*************************************************************************
* Initialise the tile map with appropriate ENTITY values
*/
MAP_BUFFER tileMap;
for (unsigned int row = 0; row < MAP_HEIGHT; row++)
{
for (unsigned int col = 0; col < MAP_WIDTH; col++)
{
tileMap [row][col] = WALL;
}
}
Essentially the entire code is used to create a tile map and output it to screen but I'm attempting to make tileMap a dynamic array in runtime.
I have tried creating one down where the tileMap is being created.
I've tried creating one just after "entity_lables" are given the typedef "ENTITY".
I've tried creating one after the "MAP_BUFFER" and "GUI_BUFFER" become aliases.
But still I'm at a loss, I have no idea on how to successfully implement a dynamic array to tileMap, and I certainly don't know the best spot to put it.
Any help would be greatly appreciated.
The syntax you are using for defining your array is for a constant sized C array. In general you should shy away from C arrays unless the size of the data is determined at compile time(and never needs to change) and the array never leaves the scope(because a C array does not retain information on its own size.)
In place of constant or dynamically sized C arrays I would suggest to use the Vector container. The Vector is a dynamically sized container that fills up from the back, the last element you have added to
std::vector<std::vector<ENTITY>>
To add the vector container to your project add the line
#include <vector>
To fill the container your loop could look like:
MAP_BUFFER tileMap;
for (unsigned int row = 0; row < MAP_HEIGHT; row++)
{
std::vector<ENTITY> column; // A column of the tile map
for (unsigned int col = 0; col < MAP_WIDTH; col++)
{
column.push_back(WALL); // Add one element to the column
}
tileMap.push_back(column); // Add the column to the tile map
}
or you could initialize the Vector to the size you want at the beginning and use your current loop to assign the tile values:
using TILE_MAP = vector<vector<ENTITY>>;
// MAP_WIDTH x MAP_HEIGHT multidimensional vector
TILE_MAP tileMap(MAP_WIDTH, vector<ENTITY>(MAP_HEIGHT));
for (unsigned int row = 0; row < MAP_HEIGHT; row++)
{
for (unsigned int col = 0; col < MAP_WIDTH; col++)
{
tileMap [row][col] = WALL;
}
}
Calling an element of a vector after it has been filled has the same syntax as an array.
tileMap[2][4]
You can also check the length of the vector:
int rows = tileMap.size();
if( rows > 0 )
int columnsInRow0 = tileMap[0].size()
While you are at it you should look into other containers like Maps and Sets since they make your life easier.
Edit:
Since you want to know how to make a dynamic array not using a vector I will give you an answer: std::vector is the C++ defined dynamically sized array. C arrays will not change size after they are defined, vector will.
However I think you are asking about the ability to define runtime constant sized arrays. So I will explain what they are and why you should not use them.
When you define the C array you are probably getting a warning saying that the expression needs to be constant.
A C array is a pointer to the stack. And the implementation of the compiletime C array is that it needs to be a constant size at compile time.
int compiletimeArray[] = { 1, 2, 3 };
// turns out c arrays are pointers
int* ptr = compiletimeArray;
// prints 2
std::cout << compiletimeArray[1];
// prints 2
std::cout << ptr[1];
// prints 2
std::cout << *(compiletimeArray + 1);
// also prints 2
std::cout << *(ptr + 1); //move pointer 1 element and de-reference
Pointers are like a whiteboard with a telephone number written on it. The same kind of issues occur as with telephone numbers; number on whiteboard has been erased, number on whiteboard has changed, recipient does not exist, recipient changed their number, service provider running out of available numbers to give new users... Keep that in mind.
To get create a runtime constant sized array you need to allocate the array on the heap and assign it to a pointer.
int size = 4;
int* runtimeArray = new int[size]; // this will work
delete[] runtimeArray; // de-allocate
size = 8; // change size
runtimeArray = new int[size]; // allocate a new array
The main difference between the stack and heap is that the stack will de-allocate the memory used by a variable when the program exits the scope the variable was declared in, on the other hand anything declared on the heap will still remain in memory and has to be explicitly de-allocated or you will get a memory leak.
// You must call this when you are never going to use the data at the memory address again
// release the memory from the heap
delete[] runtimeArray; // akin to releasing a phone number to be used by someone else
If you do not release memory from the heap eventually you will run out.
// Try running this
void crashingFunction() {
while(true)
{
// every time new[] is called ptr is assigned a new address, the memory at the old address is not freed
// 90001 ints worth of space(generally 32 or 64 bytes each int) is reserved on the heap
int* ptr = new int[90001]; // new[] eventually crashes because your system runs out of memory space to give
}
}
void okFunction() {
// Try running this
while(true)
{
// every time new[] is called ptr is assigned a new address, the old is not freed
// 90001 ints worth of space is reserved on the heap
int* ptr = new int[90001]; // never crashes
delete[] ptr; // reserved space above is de-allocated
}
}
Why use std::vector? Because std::vector internally manages the runtime array.
// allocates for you
vector(int size) {
// ...
runtimeArray = new runtimeArray[size];
}
// When the vector exits scope the deconstructor is called and it deletes allocated memory
// So you do not have to remember to do it yourself
~vector() {
// ...
delete[] runtimeArray;
}
So if you had the same scenario as last time
void vectorTestFunction() {
// Try running this
while(true)
{
std::vector<int> vec(9001); // internally allocates memory
} // <-- deallocates memory here because ~vector is called
}
If you want to use a runtime constant array I suggest the std:array container. It is like vector in that it manages its internal memory but is optimized for if you never need to add new elements. It is declared just like vector but does not contain resizing functions after its constructor.
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.
I've a segfault that I don't understand.
It always occurs at i = 0 and j between 1000 and 1100.
Here is the backtrace and all the sources required to see the problem: https://gist.github.com/Quent42340/7592902
Please help me.
EDIT: Oh I forgot. On my gist map.cpp:72 is commented. It's commented in my source code too. I did that to see where the problem came from, but even without that line, the problem is still here.
I see you allocate an array of pointers here:
m_data = new u16*[m_layers];
But, I never see you allocate the second dimension to this array. It seems like you ought to allocate the rows of your map, either as one large chunk of memory that you separate into chunks yourself, or new each row.
For example, if you add one line to your for (i ...) loop:
for(u8 i = 0 ; i < m_layers ; i++) {
m_data[i] = new u16[m_width * m_height];
If you go that route, you'll also need to upgrade your destructor:
Map::~Map() {
// WARNING: This doesn't handle the case where the map failed to load...
// Exercise for the reader.
for (u8 i = 0; i < m_layers; i++) {
delete[] m_data[i];
}
delete[] m_data;
}
An alternate approach would be to use std::array and let the C++ standard library manage that for you.
Hi I'm coding a C++ program containing a loop consuming too much unnecessary memory, so much that the computer freezes before reaching the end...
Here is how this loop looks like:
float t = 0.20;
while(t<0.35){
CustomClass a(t);
a.runCalculations();
a.writeResultsInFile("results_" + t);
t += 0.001;
}
If relevant, the program is a physics simulation from which I want results for several values of an external parameter called t for temperature. It seems that the memory excess is due to not "freeing" the space taken by the instance of my class from one execution of the loop to the following, which I thought would be automatic if created without using pointers or the new instruction. I tried doing it with a destructor for the class but it didn't help. Could it be because the main memory use of my class is a 2d array defined with a new instruction in there?
Precision, it seems that the code above is not the problem (thanks for the ones pointing this out) so here is how I initiate my array (by the largest object in my CustomClass) in its constructor:
tab = new int*[h];
for(int i=0; i<h; i++) {
tab[i] = new int[v];
for(int j=0; j<v; j++) {
tab[i][j] = bitd(gen)*2-1; //initializing randomly the lattice
}
}
bitd(gen) is a random number generator outputing 1 or 0.
And also, another method of my CustomClass object doubles the size of the array in the following way:
int ** temp = new int*[h];
for(int i=0; i<h; i++) {
temp[i] = new int[v];
for(int j=0; j<v; j++) {
temp[i][j] = tab[i/2][j/2];
}
}
delete[] tab;
tab = temp;
Could there be that I should free the pointer temp?
You're leaking memory.
Could there be that I should free te pointer temp?
No. After you allocate the memory for the new array of double size and copy the contents, you should free the memory that tab is pointing to. Right now, you're only deleting the array of pointers with delete [] tab; but the memory that each of those pointers points to is lost. Run a loop and delete each one. Only then do tab = temp.
Better still, use standard containers that handle memory management for you so you can forget messing with raw pointers and focus on your real work instead.
I got a problem that is beyond my knowledge. I'm working on a HGE project, but this is a c++ issue, not the HGE engine itself.
The question:
I want to create a 2D array with 3 different animations on 5 different turtles. However, I need to use a constructor in HGE something like this;
turtleAnim[i] = new hgeAnimation( turtleTexture, 6, 6, 0, 0, 110, 78 )
But I don't know how to do it! All examples on the interwebz handle the problem as if it got a default constructor. Something like this:
in class:
#define TURTLECOUNT 5
#define TURTLEANIMATIONS 3
private:
hgeAnimation** turtleAnim;
in the.cpp
turtleAnim= new hgeAnimation*[TURTLECOUNT];
for(int i=0; i<TURTLECOUNT; i++)
{
turtleAnim[i]= new hgeAnimation[TURTLEANIMATIONS]; // Uses default constructor. I don't want that cuz it doesn't exists.
turtleAnim[i]->Play();
}
First, you have to decide whether you want your objects on the stack or the heap. Since they're objects, you probably want them on the heap, which means your 2D array will have 3 stars, and you will access the animations like this:
hgAnimation* theSecondAnimOnTheFourthTurtle = turtleAnim[4][2];
theSecondAnimOnTheFourthTurtle->DoSomething();
If that's what you want, then first you make the matrix of pointers.
hgeAnimation*** turtleAnim = new hgeAnimation**[TURTLECOUNT];
Then you can loop through the turtles. For each turtle, you make an array of pointers to the animations. For each element of that array, you make the animation itself.
for (int turt=0; turt<TURTLECOUNT; ++turt) {
turtleAnim[turt] = new hgeAnimation*[TURTLEANIMATIONS];
for (int ani=0; ani<TURTLEANIMATIONS; ++ani) {
turtleAnim[turt][ani] = new hgeAnimation(parameter1, par2, par3);
}
}
If that looks tricky, deleting all the arrays will be a pain too:
for (int turt=0; turt<TURTLECOUNT; ++turt) {
for (int ani=0; ani<TURTLEANIMATIONS; ++ani) {
delete turtleAnim[turt][ani];
}
delete[] turtleAnim[turt];
}
delete[] turtleAnim;
The fact that this is tricky is a good sign that there's probably a more simple way to design it.
How about a turtle class that has a member like:
class ATurtle {
private:
std::vector<hgeAnimation*> myAnimations;
Then in your class's constructor, you can do whatever you want in order to make the animations.
ATurtle::ATurtle(par1, par2, par3) {
myAnimations.push_back( new hgeAnimation(par1, x, y) );
myAnimations.push_back( new hgeAnimation(par2, z, a) );
myAnimations.push_back( new hgeAnimation(par3, b, c) );
}
That way, you can make your turtles in a single array:
ATurtle* turtles[TURTLECOUNT];
for (int t=0; t<TURTLECOUNT; ++t) {
turtles[t] = new ATurtle(par1, par2);
}
And in your turtle class, you would access the animations like so:
(*(myAnimations.at(1)))->DoSomething();
or
std::vector<hgAnimation*>::iterator i, end=myAnimations.end();
for (i=myAnimations.begin(); i!=end; ++i) {
(*i)->DoSomething();
}
You will still have to call delete on each element of your vector in this case, though, since you called new for every element.
ATurtle::~ATurtle() {
std::vector<hgAnimation*>::iterator i, end=myAnimations.end();
for (i=myAnimations.begin(); i!=end; ++i) {
delete (*i);
}
}