Array of Pointers to Objects

Started by
19 comments, last by snk_kid 18 years, 11 months ago
Quote:Original post by Raeldor
Thanks, I almost having it working now. Only thing that is not compiling at the moment is...

pTiles=new (Tile*)[nTilesAcross*nTilesDown];

I get the error...

f:\My Documents\Visual Studio Projects\test2\terrain.cpp(18): error C2143: syntax error : missing ';' before '['

Remove the brackets around Tile*. It looks like Andrew Russell is using gcc, which can cope with that syntax, but Visual C++ chokes on it. I'm not actually sure if it's valid syntax or not - looks too much like a call to placement new and this may be what confuses the compiler.

Enigma
Advertisement
Quote:Original post by Enigma
Quote:Original post by Raeldor
Thanks, I almost having it working now. Only thing that is not compiling at the moment is...

pTiles=new (Tile*)[nTilesAcross*nTilesDown];

I get the error...

f:\My Documents\Visual Studio Projects\test2\terrain.cpp(18): error C2143: syntax error : missing ';' before '['

Remove the brackets around Tile*. It looks like Andrew Russell is using gcc, which can cope with that syntax, but Visual C++ chokes on it. I'm not actually sure if it's valid syntax or not - looks too much like a call to placement new and this may be what confuses the compiler.

Enigma


Awesome, that did the trick. I think I am good to go now.

Thanks all for your help!
Quote:Original post by Raeldor
pTiles=new (Tile*)[nTilesAcross*nTilesDown];


Quote:Original post by Raeldor
pTiles=new ((Tile*)[nTilesAcross*nTilesDown]);


Quote:Original post by anonuser
Tile **pTiles = new Tile[10][nTileAcross*nTilesDown];


These are all invalid syntax in standard C++, in the last one the types don't match.

@Raeldor if your making arrays of pointers just to get round the limitations of C-style dynamic arrays using operators new i.e. your type does not have a default constructor or you want to allocate memory first then incrementally construct/initialize elements instead of redundantly having all elements default constructed on first creation.

Doing it with an arrays of pointers is not an efficient method. What you really want is a dynamic array of the actual type but separate allocation/de-allocation & construction/destruction you can do this in C++ with operators new/delete but its very low-level and advance C++, potentially prone to error.

This is one of the reasons why we have std::vector it essentially takes care of all this for you among other things, guaranteed contiguousness of elements.

In both cases this can be done for multidimensional arrays too.
Quote:
These are all invalid syntax in standard C++, in the last one the types don't match.

@Raeldor if your making arrays of pointers just to get round the limitations of C-style dynamic arrays using operators new i.e. your type does not have a default constructor or you want to allocate memory first then incrementally construct/initialize.

Doing it with an arrays of pointers is not an efficient method. What you really want is a dynamic array of the actual type but separate allocation/de-allocation & construction/destruction you can do this in C++ with operators new/delete but its very low-level and advance C++, potentially prone to error.

This is one of the reasons why we have std::vector it essentially takes care of all this for you among other things, guaranteed contiguousness of elements.

In both cases this can be done for multidimensional arrays too.


Just to recap, my code now looks like...

// create tiles
pTiles=new Tile*[nTilesAcross*nTilesDown];
for (int y=0; y < nTilesDown; y++)
for (int x=0; x < nTilesAcross; x++)
pTiles[y*nTilesAcross+x]=new Tile(nTileSize, x*nTileSize, y*nTileSize);

to initialize and...

// release tiles
for (int y=0; y < nTilesDown; y++)
for (int x=0; x < nTilesAcross; x++)
{
if (pTiles[y*nTilesAcross+x] != NULL)
delete pTiles[y*nTilesAcross+x];
}

// delete pointer array
delete [] pTiles;

Is this really bad c++? What additional benefit would std::vector give me considering I only want to index into these tiles using x/y values?

Thanks
The code you have posted requires ((nTilesAcross × nTilesDown) + 1) memory allocations. One for the array and one for each Tile. Memory allocation is usually an expensive operation, although it doesn't usually matter too much for instances like this since this initialisation is likely to only be done once per level/game. Each access to a tile also requires two levels of indirection. One to index into the array and one to index from the pointer to the actual Tile. Using std::vector you could reduce this to just two memory allocations and reduce the levels of indirection to just one:
std::vector< Tile > tiles;tiles.reserve(nTilesAcross * nTilesDown);for (int y=0; y < nTilesDown; y++){	for (int x=0; x < nTilesAcross; x++)	{		 tiles.push_back(Tile(nTileSize, x*nTileSize, y*nTileSize));	}}// example usetiles[(y * nTilesAcross) + x].doSomething();

This also has the added benefit that the vector will automatically clean up it's memory when it leaves scope, so there is no need to delete([]) anything.

Enigma
Quote:Original post by Enigma
The code you have posted requires ((nTilesAcross × nTilesDown) + 1) memory allocations. One for the array and one for each Tile. Memory allocation is usually an expensive operation, although it doesn't usually matter too much for instances like this since this initialisation is likely to only be done once per level/game. Each access to a tile also requires two levels of indirection. One to index into the array and one to index from the pointer to the actual Tile. Using std::vector you could reduce this to just two memory allocations and reduce the levels of indirection to just one:
*** Source Snippet Removed ***
This also has the added benefit that the vector will automatically clean up it's memory when it leaves scope, so there is no need to delete([]) anything.

Enigma


Wow, that's pretty sweet looking code. I will definitely look into the vectors.

Thanks again!
Just to add to the last comment, doing the arrays of pointers idiom to get round default construction increases the chance of memory fragmentation thus reducing efficency because you will not have real contiguousness of elements any more.

[Edited by - snk_kid on May 28, 2005 6:28:37 PM]
Boost.MultiArray

Example:

#include "boost/multi_array.hpp"#include <cassert>int main () {  // Create a 3D array...  typedef boost::multi_array<double, 3> array_type;  typedef array_type::index index;  // ... that is 3 x 4 x 2  array_type A(boost::extents[3][4][2]);  // Assign values to the elements  int values = 0;  for(index i = 0; i != 3; ++i)     for(index j = 0; j != 4; ++j)      for(index k = 0; k != 2; ++k)        A[j][k] = values++;  // Verify values  int verify = 0;  for(index i = 0; i != 3; ++i)     for(index j = 0; j != 4; ++j)      for(index k = 0; k != 2; ++k)        assert(A[j][k] == verify++);  return 0;}
Quote:Original post by Enigma
It looks like Andrew Russell is using gcc, which can cope with that syntax, but Visual C++ chokes on it.

Actually, Andrew Russell was just typing code in the browser [wink]. Helping with plain-ol' syntax errors is kinda hard when you don't check your code.
This is kind of going back to the very beginning, but when you delete an array of pointers, shouldn't you just delete the array itself? Like this:

Tile** tiles = whatever;
// do something
delete tiles;

Instead of deleting each one individually. This is irrelevant, I just was curious 'cause that's how I would have done it. Am I wrong?

This topic is closed to new replies.

Advertisement