initiating a 2d array of a class

M

Mark

uhhmmm... not really sure how to word this.
i cant get get this to compile.. i'm not sure what the proper syntax to
do this is.. hopefully it's self explanatory.

here's my class:
------
class TileMap
{
public:

int xw, yw;
int tw, th;
int rows, cols;
int fullrows, fullcols;
int minX, minY, maxX, maxY;

TileMapCell **grid;

TileMap(int rows, int cols, int xw, int yw) : rows(rows),
cols(cols), xw(xw), yw(yw)
{
tw = xw*2;
th = yw*2;
fullrows = rows+2;
fullcols = cols+2;
minX = tw;
minY = th;
maxX = tw + (rows*tw);
maxY = th + (rows*th);
}

TileMapCell GetTile_S(int x, int y)
{
return grid[int(x/tw)][int(y/th)];
}

TileMapCell GetTile_V(Vector2 v)
{
return grid[int(v.x/tw)][int(v.y/th)];
}

TileMapCell GetTile_I(int x, int y)
{
return grid[x][y];
}

void GetIndex_S(Vector2 v, int x, int y)
{
v.x = int(x/tw);
v.y = int(y/th);
}

void GetIndex_V(Vector2 v, Vector2 p)
{
v.x = int(p.x/tw);
v.y = int(p.y/th);
}

void Building()
{
int x = xw;
int y = yw;
int fullrows = fullrows;//the ACTUAL size of the grid, including
border tiles
int fullcols = fullcols;
int rows = rows;
int cols = cols;

//build raw tiles
for(int i = 0; i < fullrows; i++)
{
grid = new TileMapCell[fullcols]; // <--- need help here!!!
for(int j = 0; j < fullcols; j++)
{
grid[j] = new TileMapCell(i,j,x,y,xw,yw);
y += th;
}
x += tw;
y = yw;
}
}
};
--------------------
the problem is in here:
------------------
//build raw tiles
for(int i = 0; i < fullrows; i++)
{
grid = new TileMapCell[fullcols]; // <--- need help here!!!
for(int j = 0; j < fullcols; j++)
{
grid[j] = new TileMapCell(i,j,x,y,xw,yw);
y += th;
}
x += tw;
y = yw;
}
-----------------
and incase you were about to ask:
------------
class TileMapCell
{
public:

int ID;
int CTYPE;
int i,j; // index of tile in grid

TileMapCell *nU, *nD, *nL, *nR; // neighboring tiles
int eU, eD, eL, eR; // edge info

float gx; // environmental properties
float gy;
float d;

TileMapCell *next, *prev;

Vector2 pos;

int xw, yw;

float minx, maxx, miny, maxy;

int signx, signy, sx, sy;

TileMapCell(int i, int j, float x, float y, int xw, int yw) : i(i),
j(j), xw(xw), yw(yw)
{
pos.set(x,y);

gx = 0;
gy = GRAV;
d = DRAG;

nU = nD = nL = nR = NULL;
eU = eD = eL = eR = EID_OFF;
next = prev = NULL;

minx = pos.x - xw;
maxx = pos.x + xw;
miny = pos.y - yw;
maxy = pos.y + yw;

signx = signy = sx = sy = 0;
}

void LinkU(TileMapCell *t)
{
nU = t;
}
void LinkD(TileMapCell *t)
{
nD = t;
}
void LinkL(TileMapCell *t)
{
nL = t;
}
void LinkR(TileMapCell *t)
{
nR = t;
}
};
-------------------
and before you tell me

grid = new TileMapCell[fullcols];

doesnt work because there is no TileMapCell() constructor.... I know.
but it shouldnt really be constructing anything at that point... right?

if you need more info.. just leave a message.

thanks for the help.
 
G

Gianni Mariani

Mark wrote:
....
and before you tell me

grid = new TileMapCell[fullcols];

doesnt work because there is no TileMapCell() constructor.... I know.
but it shouldnt really be constructing anything at that point... right?

if you need more info.. just leave a message.


It appears you want to create an array of pointers to

TileMapCell.grid = new TileMapCell*[fullcols];
 
M

Mark

hmm..?

thanks for the fast reply... but that doesn't make any sense...

basically if # represents a cell, if my understanding is correct, then
grid would represent

#
#
#
#
....

and we want to add some cells to the x dimension...

###
###
###
###
....

but what you're saying is we add a 2D something or other ( *[] ) to
each row??


anyways.. i tried that, and

grid = new TileMapCell*[fullcols]; // <--- need help here!!!

doesnt compile either.
says:
cannot convert `TileMapCell**' to `TileMapCell*' in assignment

so like i said.. its trying to turn something with 2 dimensions into
something with 1...
 
A

Alf P. Steinbach

* Mark:
uhhmmm... not really sure how to word this.
i cant get get this to compile.. i'm not sure what the proper syntax to
do this is.. hopefully it's self explanatory.

Solution: use standard library classes, and use the Boost library, and
_don't_ do raw arrays or raw pointers.


here's my class:
------
class TileMap
{
public:

int xw, yw;
int tw, th;
int rows, cols;
int fullrows, fullcols;
int minX, minY, maxX, maxY;

Surely you don't want the above members public. Make them private.

TileMapCell **grid;

Go to <url: http://www.boost.org/libs/multi_array/doc/user.html>.

Hth.,

- Alf
 
D

David White

I haven't looked through your code at all. I've only tried to compile it
(after making various repairs), and there appears to be two main problems:
1. Class TileMapCell does not have a default constructor, so you cannot
create an array of them.
i.e., grid = new TileMapCell[fullcols];

2. Your types don't match in: grid[j] = new TileMapCell(i,j,x,y,xw,yw);
If grid is TileMapCell**, then grid is TileMapCell* and grid[j] is a
TileMapCell object, but "new TileMapCell(i,j,x,y,xw,yw);" returns
TileMapCell*, so you are trying to convert a pointer into an actual object,
which of course doesn't work. Assuming that your pointers are valid, try
this instead: grid[j] = TileMapCell(i,j,x,y,xw,yw);
Not that that will create a temporary TileMapCell to which the array element
will be assigned and then the temporary will be destroyed.

It might be worth remembering that you don't have to use 'new' to create
everything. In fact, it's best to avoid it whenever you reasonably can.

DW
 
M

Mark

David said:
1. Class TileMapCell does not have a default constructor, so you cannot
create an array of them.
i.e., grid = new TileMapCell[fullcols];

doesnt work because there is no TileMapCell() constructor.... I know.
but it shouldnt really be constructing anything at that point... right?

David said:
It might be worth remembering that you don't have to use 'new' to create
everything. In fact, it's best to avoid it whenever you reasonably can.

I'll try removing the "new"... but uhm... I don't think it complains
about that line.

I believe I've done something like this before... I guess I'll have to
dig through my old code.

I hate using those crazy libraries where it isn't necessary...
sure, *maybe* they can make some things easier... but their syntax is
nuts, and they have all this extra unecessary baggage. there is a way
to do it...

like, what is all this crap just to create a 3d array?

typedef boost::multi_array<double, 3> array_type;
typedef array_type::index index;
array_type A(boost::extents[3][4][2]);

and what benefits does it even have??

i guess i'd have to look into it before i bash it, but i'm not looking
for extra features anyway.

but yes, thanks... i shall, give this a shot if worse comes to worse.
Surely you don't want the above members public. Make them private.

well. sure i do. why not?

the only reason i can see for *not* having them public is so that one
doesn't "accidentally" change their values.
but the only person who is going to be using this class is me.
and i'd like to easily read and modify them without having to make 20
different "getters" and "setters"
especially for debugging purposes...

i don't see why people always insist that the majority of members are
private. there's no real point unless you are going to publicly
distribute it....

not to critique your post or anything :D i appreciate your help.
(btw, if you can give me a better reason, i'm all ears. i'm open
minded, but that's the way i see it as of now)
 
A

Alf P. Steinbach

* Mark:
* Alf P. Steinbach:

I hate using those crazy libraries where it isn't necessary...
sure, *maybe* they can make some things easier... but their syntax is
nuts, and they have all this extra unecessary baggage. there is a way
to do it...

Boost is very far from being a crazy library. Many parts of Boost are
slated for inclusion in the standard library with the next version of
the C++ standard. Those parts include fixed size arrays, but currently
not the multi-dimensional arrays.

like, what is all this crap just to create a 3d array?

typedef boost::multi_array<double, 3> array_type;
typedef array_type::index index;
array_type A(boost::extents[3][4][2]);

and what benefits does it even have??

Those three lines do all that you're (unsuccessfully) trying to do in
umpteen lines of code, and the Boost code has been subjected to rigorous
review so that you can trust it.

But feel free to prefer weeks of debugging instead.

i guess i'd have to look into it before i bash it, but i'm not looking
for extra features anyway.

but yes, thanks... i shall, give this a shot if worse comes to worse.


well. sure i do. why not?

the only reason i can see for *not* having them public is so that one
doesn't "accidentally" change their values.
but the only person who is going to be using this class is me.
and i'd like to easily read and modify them without having to make 20
different "getters" and "setters"

Providing "getters" and "setters" is not just just as bad, it's even
worse.

Make those members private and _keep_ them private.

No per member getters, no per member setters: the client code should not
have to know anything about the internal members, or whether you have
implemented your class by having it communicate with a matrix-savvy
chimpanzee who holds the state -- for example.

especially for debugging purposes...

i don't see why people always insist that the majority of members are
private. there's no real point unless you are going to publicly
distribute it....

It saves you work.
 
D

David White

Mark said:
David said:
1. Class TileMapCell does not have a default constructor, so you cannot
create an array of them.
i.e., grid = new TileMapCell[fullcols];

doesnt work because there is no TileMapCell() constructor.... I know.
but it shouldnt really be constructing anything at that point... right?


Wrong. You are trying to create an array of TileMapCell objects. That's what
the 'new' expression is doing. You can't have an object array that doesn't
contain any objects yet (using conventional means, anyway), if that's what
you were hoping for.

If you want to have (in effect) a 2D array of TileMapCells but you don't
want to default-construct them initially and replace them with variably
constructed ones later, and you do want to persist with bare pointers to
contain them, then you can use more indirection:
TileMapCell ***grid;
....
grid = new TileMapCell**[fullrows];
for(int i = 0; i < fullrows; i++)
{
grid = new TileMapCell*[fullcols];
for(int j = 0; j < fullcols; j++)
{
grid[j] = new TileMapCell(i,j,x,y,xw,yw);
....

(Don't forget to delete all objects and pointer arrays when you are done
with them; requires nested loops also).

If this doesn't look more appealing than what you already have, then fix
what you have according to my first reply, or, as has been wisely suggested
elsewhere, use a proper container that does all the messy memory management
for you.

BTW, to illustrate how fraught it can be to work with umpteen pointers
several nestings deep, your original code disastrously omits this crucial
line before the loops:
grid = new TileMapCell*[fullrows];
I'll try removing the "new"... but uhm... I don't think it complains
about that line.

Humour me and try compiling it again, but this time include a default
constructor so the earlier line compiles.

DW
 
N

Neil Cerutti

uhhmmm... not really sure how to word this.
i cant get get this to compile.. i'm not sure what the proper syntax to
do this is.. hopefully it's self explanatory.

here's my class:
------
class TileMap
{
public:

int xw, yw;
int tw, th;
int rows, cols;
int fullrows, fullcols;
int minX, minY, maxX, maxY;

TileMapCell **grid;

That's a bewildering schmorgasbord of public variables. If
they're meant to be manipulated and viewed by users, you should
probably use better names, or at least document them.

My guess is you don't need any of them except for rows, cols, and
grid.

If you're going to make everything in a class public (and
actually you shouldn't), just use a struct.
TileMap(int rows, int cols, int xw, int yw) : rows(rows),
cols(cols), xw(xw), yw(yw)
{
tw = xw*2;
th = yw*2;
fullrows = rows+2;
fullcols = cols+2;
minX = tw;
minY = th;
maxX = tw + (rows*tw);
maxY = th + (rows*th);
}

You could've initialized all of those members in the
initialization list.

Finally, you initialized everything except grid, which is the one
you'd ideally like to see initialized in the constructor.
TileMapCell GetTile_S(int x, int y)
{
return grid[int(x/tw)][int(y/th)];
}

TileMapCell GetTile_V(Vector2 v)
{
return grid[int(v.x/tw)][int(v.y/th)];
}

TileMapCell GetTile_I(int x, int y)
{
return grid[x][y];
}

void GetIndex_S(Vector2 v, int x, int y)
{
v.x = int(x/tw);
v.y = int(y/th);
}

void GetIndex_V(Vector2 v, Vector2 p)
{
v.x = int(p.x/tw);
v.y = int(p.y/th);
}

I'm assuming Vector2 is a reference type, or those functions do
nothing.
void Building()

You probably ought to call this function in the constructor. Or
move this code there.
{
int x = xw;
int y = yw;
int fullrows = fullrows;//the ACTUAL size of the grid, including
border tiles
int fullcols = fullcols;
int rows = rows;
int cols = cols;

The British are comin'! Hide the yer women, children an' member
names! ;-)


You must initialize grid before proceeding.

grid = new (TileMapCell*)[fullrows];

Then proceed to initialize those pointers.

//build raw tiles
for(int i = 0; i < fullrows; i++)
{
grid = new TileMapCell[fullcols]; // <--- need help here!!!


Needs a default constructor.
for(int j = 0; j < fullcols; j++)
{
grid[j] = new TileMapCell(i,j,x,y,xw,yw);
y += th;
}
x += tw;
y = yw;
}
}
};


Here's how it might look:

grid = new (TileMapCell*)[fullrows];
for (int i = 0; i < fullrows; ++i)
{
/* Hint: Won't work without a default constructor for
* TileMapCell. Constructs an array of TileMapCells. You'll
* need a different grid data type if you want to avoid the
* default construction, e.g., pointer to pointer to grid */
grid = new TileMapCell[fullcols];
for (int j = 0; j < fullcols; ++j)
{
/* Assign the correct values to the members of the default
* constructed TileMapCell instances. */
grid[j].i = i;
grid[j].j = j;
/* etc. */
}
}
and incase you were about to ask:

No way. I can't watch any more. ;-)
grid = new TileMapCell[fullcols];

doesnt work because there is no TileMapCell() constructor.... I
know. but it shouldnt really be constructing anything at that
point... right?


No, you're asking new to create an array of objects. Those
objects must be constructed.
 
N

Neil Cerutti

grid = new (TileMapCell*)[fullrows];
for (int i = 0; i < fullrows; ++i)
{
/* Hint: Won't work without a default constructor for
* TileMapCell. Constructs an array of TileMapCells. You'll
* need a different grid data type if you want to avoid the
* default construction, e.g., pointer to pointer to grid */

I meant "pointer to pointer to pointer to grid" there.
 
N

Neil Cerutti

grid = new (TileMapCell*)[fullrows];
for (int i = 0; i < fullrows; ++i)
{
/* Hint: Won't work without a default constructor for
* TileMapCell. Constructs an array of TileMapCells. You'll
* need a different grid data type if you want to avoid the
* default construction, e.g., pointer to pointer to grid */

I meant "pointer to pointer to pointer to grid" there.

Arrgh! No I didn't.
 
D

Default User

Alf P. Steinbach wrote:

Boost is very far from being a crazy library. Many parts of Boost are
slated for inclusion in the standard library with the next version of
the C++ standard. Those parts include fixed size arrays, but
currently not the multi-dimensional arrays.

Which makes them third-party libraries at this point. No one should be
forced to use them if they don't want to.


Brian
 
K

Kai-Uwe Bux

Default said:
Alf P. Steinbach wrote:



Which makes them third-party libraries at this point. No one should be
forced to use them if they don't want to.

And who exactly is forcing someone here to use them? All that happened is:

a) Alice asked "how do you solve problem X"?
b) Bob answered "use boost::...".
c) Alice said: I don't like that.

Now, if Alice is arbitrarily restricting the search space for solutions to
the problem, Bob might be less willing to lend a helping hand. But that is
far from forcing.


Best

Kai-Uwe
 
M

Mark

woah.. that's a lot to respond to.. so i'm not going to quote you all,
but in kind of a collective response...

uhhhmmm.. ok, so it's evident i *do* need a default constructor with
the way i was trying to write it.. but, in that case, i guess i wrote
it completely wrong :)

yes, the code is kind of messy at this point.. but i just want it to
run at this point, then i'll clean it up. this is called the "learning
process" :)

i've tried lots of approaches.. tried keeping the code all clean and
such..but eventually you run into a snag, and it all goes to hell.

so, Alf P. Steinbach, you do make boost sound more appealing.

but.. i still think the best way to solve a problem, is to understand
the problem. in other words, sure, i might be able to get away with
using boost... but how do i know what the heck boost is doing? if i
*try* to write the code myself, i might get an understanding of how
boost, and other container classes work, which puts me in a better
position to solve and tackle future problems. i like to write as much
as i possibly can by hand...

i like Neil Cerutti's solution best.. it's clear, and somewhat simple
:p

and uhm.. yes.. i intend on calling "Building" inside the
constructor... i'm actually attempting to follow some code written in
Flash's ActionScript... so i'm writing it as similar as possible, but
in C++ of course. Building() will be about 9 times as long as it is
now....

... and what does all this junk do? eventually, it might produce some
nice 2d collision detection. with slopes, and semi circles, and all
that fun stuff.

thanks for all your help guys :) really appreciate it.
 
M

Mark

tada... my new solution.
----
grid = new TileMapCell*[fullrows];
for(int i = 0; i < fullrows; i++)
{
grid = new TileMapCell[fullcols];
for(int j = 0; j < fullcols; j++)
{
grid[j].set(i,j,x,y,xw,yw);
y += th;
}
x += tw;
y = yw;
}
 
D

David White

Mark said:
.. and what does all this junk do? eventually, it might produce some
nice 2d collision detection. with slopes, and semi circles, and all
that fun stuff.

I don't know whether it's applicable in your case, but collisions can
detected mathematically, at least in some cases. I wrote a program for fun a
long time ago that had two "spheres" (really circles) on the screen moving
around and bouncing off the edges of the screen and off each other,
according to Newtonian physics. Given the radii, positions and velocities of
the circles, the collision point, if any, could be found precisely by
solving a very long quadratic equation.

DW
 
M

Mark

hm.. well it's easy to detect if two circles are overlapping.. but to
have them react appropriately is much more difficult.
anyways... i have all the code here.. except in actionscript. but
proper tutorials shouldnt be hard to come by either...

but uhm...
---
//build raw tiles
grid = new TileMapCell*[fullrows];
for(int i = 0; i < fullrows; i++)
{
grid = new TileMapCell[fullcols];
for(int j = 0; j < fullcols; j++)
{
grid[j].Init(i,j,x,y,xw,yw);
y += th;
}
x += tw;
y = yw;
}
---

doesnt run so well after all. Init(...) never does get called.....
crashes somewhere inbetween.

erm.. dare i ask for suggestions?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top