Aeonstrife
Aeonstrife

Reputation: 673

2D array help in C++

So I made my own class in order to hold a 3D vertex. That basically looks like:

class Vertex                                    // Vertex Class
{
public:
    float x;                                // X Component
    float y;                                // Y Component
    float z;                                // Z Component

    float getX() {
        return x;
    }
    float getY() {
        return y;
    }
    float getZ() {
        return z;
    }
};

Now I need to make a 2D array of these but when I initialize it it won't work. Basically each row will be a face of a polygon. And each column will contain a vertex of that row. So if one row is

(0,0,0) (1, 1, 1) (3, 3, 3) (4,4,4);

Then that row will represent a face with vertices (0,0,0) (1, 1, 1) (3, 3, 3) (4,4,4);

Now when I try to initialize it using

Vertex faces = new Vertex[num_faces][4];

It work work. This seems pretty simple so what am I doing wrong?

EDIT: I changed it to

Vertex *faces = new Vertex[num_faces][4];

and I get this error:

cannot convert from 'Vertex (*)[4]' to 'Vertex *'

Upvotes: 1

Views: 1123

Answers (4)

FrankH.
FrankH.

Reputation: 18247

"Twodimensional arrays" are of evil ... they often don't quite do what you're hoping to achieve.

Thing is, to compile your code, it either needs to turn the indices around, in which case you get:

Vertex *faces[4] = {
    new Vertex[num_faces],
    new Vertex[num_faces],
    new Vertex[num_faces],
    new Vertex[num_faces]
};

Or you'd have to use the code that mkaes posted.

The problem with this is that it requires at least four (if not five) calls to new(), any of which theoretically could fail. You can also not delete this "thing" in a single operation.

For fully "struct-like" objects as this one, one can do the following trick:

char *memblk =
    malloc(num_faces * 4 * sizeof(Vertex) + num_faces * sizeof(Vertex *));

Vertex **faces = static_cast<Vertex **>memblk;
Vertex *first = static_cast<Vertex *>(memblk + num_faces * sizeof(Vertex *));

for(i = 0; i < num_faces; first += 4, i++)
    faces[i] = first;

where you allocate a single block of memory large enough to hold:

  1. an array of Vertex * of size num_faces, and
  2. num_faces arrays of Vertex of size 4.

and then initialize the former to contain the respective starting addresses.

To "delete" this, you'd need to use again the C function free(faces) - but it's ok with a single call.

The above is actually quite efficient and corresponds closely to the sort of low-level representation that e.g. OpenGL Vertex buffer objects use for the data (in fact, it can be made to match those).

Upvotes: 0

Robᵩ
Robᵩ

Reputation: 168876

Never use arrays when vectors will do the same thing. The data structure you need is std::vector<std::vector<Vertex> >.

class Vertex {
    ...
    Vertex(float x, float y, float z) : x(x), y(y), z(z) {}
};

int main() {
    // a 1D array of vertices is a polygon
    std::vector<Vertex> square;
    square.push_back(Vertex(0, 0, 0));
    square.push_back(Vertex(0, 1, 0));
    square.push_back(Vertex(1, 1, 0));
    square.push_back(Vertex(1, 0, 0));

    // Another square, in a different plane
    std::vector<Vertex> square1;
    square1.push_back(Vertex(0, 0, 1));
    square1.push_back(Vertex(0, 1, 1));
    square1.push_back(Vertex(1, 1, 1));
    square1.push_back(Vertex(1, 0, 1));

    // A 2D array of vertices is a polyhedron.
    std::vector<std::vector<Vertex> > cube;
    cube.push_back(square);
    cube.push_back(square1);
    // need four more sides
}

Notice the complete lack of pointers, malloc or new.

For increased readability, I'd recommend typedef std::vector<Vertex> polygon, typedef std::vector<polygon> polyhedron, and liberal use of the functions from boost::assign.

Upvotes: 0

mkaes
mkaes

Reputation: 14129

You need to declare a two dimensional array for what you want to archive.

Vertex **faces = new Vertex*[num_faces];
for(int i=0; i < num_faces; ++i)
    faces[i] = new Vertex[4];

Or of course when you num_faces is compile time constant you can just declare the array like this.

Vertex faces[num_faces][4];

A good resource of dynamic arrays with multiple dimensions can be found in c++-faq lite

Upvotes: 0

fredoverflow
fredoverflow

Reputation: 263360

cannot convert from 'Vertex (*)[4]' to 'Vertex *'

The compiler is already telling you what you need to know, just change the type of faces:

Vertex (*faces)[4] = new Vertex[num_faces][4];

Upvotes: 3

Related Questions