user
user

Reputation: 6797

c++ two dimensional array question

I would like to create something like a pointer to a 2 dimensional array of pointers (with the width and the height of x).
Will this code do what I expect? (Create array elements, writing out some information about them, then release all the allocated memory.)

int main(int argc, char** argv) {
    int x = 3;
    Node ***array = new Node**[x];
    for (int i = 0; i < 3; i++) {
        array[i] = new Node*[x];
        for (int j = 0; j < x; j++) {
            array[i][j] = new Node(i, j); /* Node::Node(int row, int col) */
        }
    }
    /* ....... */
    for (int i = 0; i < x; i++) {
        for (int j = 0; j < x; j++) {
            cout << array[i][j]->row << ", " << array[i][j]->col << endl;
        }
    }
    /* ....... */
    for (int i = 0; i < x; i++) {
        for (int j = 0; j < x; j++) {
            delete array[i][j];
            //array[i][j] = NULL;
        }
        delete[] array[i];
        //array[i] = NULL;
    }
    delete[] array;
    //array = NULL;
    return 0;
}

Or should I create a vector of vector of pointers to Node objects?
Or else should I allocate my objects on the stack?

(I'm using pointers, because in Java or C#, you have to always use the new keyword when creating an object (however, I don't think all the objects are in the heap memory), and I read that there are more space available on the heap.)

An other reason I use pointers with the new keyword, that I would like to create multiple pointers to the same object. Should I create one object on stack, and just create pointers to that object?

Upvotes: 1

Views: 1314

Answers (3)

Emile Cormier
Emile Cormier

Reputation: 29209

I recommend that you use vector< vector<Node> >, boost::multi_array, or you can roll-up your own dynamic 2D array class (it's not that hard) that is a wrapper around a flat 1D std::vector.

All of the above solutions will store your Node objects in the heap, and will take care of cleaning up memory.

Here's an example of a simple Matrix class that is a wrapper around std::vector<T>:

#include <iostream>
#include <vector>

template <class T>
class Matrix
{
public:
    Matrix() : width_(0), height_(0), vec_(0) {}

    Matrix(size_t width, size_t height)
        : width_(width), height_(height), vec_(width*height) {}

    size_t size() const {return vec_.size();}

    size_t width() const {return width_;}

    size_t height() const {return height_;}

    // Clears all preexisting data
    void resize(size_t width, size_t height)
        {width_ = 0; height_ = 0; vec_.clear(); vec_.resize(width*height);}

    void clear() {width_ = 0; height_ = 0; vec_.clear();}

    T& operator()(size_t col, size_t row) {return vec_[row*width_ + col];}

    const T& operator()(size_t col, size_t row) const
        {return vec_[row*width_ + col];}

private:
    size_t width_;
    size_t height_;
    std::vector<T> vec_;
};

int main()
{
    Matrix<double> a(3, 4);
    a(1, 2) = 3.1415;
    std::cout << a(1,2) << "\n";
}

It uses operator() to mimic the array[2][4] syntax of c-style multidimensional arrays. You don't have to worry about shallow copies, freeing memory, etc, because vector already takes care of that.

Upvotes: 4

Asher Dunn
Asher Dunn

Reputation: 2394

Your code looks correct, but I would recommend creating a vector of vectors of Node objects The vector class manages its own memory, so you never have to worry about forgetting to delete anything.

You don't even have to make it a vector of vectors of Node pointers. If you say my_vector.push_back(my_node), it copies my_node into the vector's heap-allocated memory. If you return the vector from your function, the node goes with it (it isn't lost at the end of the function, like a stack-allocated object). For example:

// declare a vector of nodes on the stack
vector<node> nodes;

// declare a Node object on the stack
Node my_node(/*arguments*/);

// copy my_node (on the stack) into the vector's memory (on the heap)
nodes.push_back(my_node);

// (return 'nodes' from this function and store it somewhere)

Note that the Node in nodes is a different object than my_node. If you made my_node with new instead, push_back() would copy the pointer (not the object itself), and the object in the vector would be same one you created with new. If you do that, you own the object, and you have to remember to delete it when you're finished. If you let the vector own the object (as in my code example), it will handle that for you.

Upvotes: 0

Andy Finkenstadt
Andy Finkenstadt

Reputation: 3587

Have you considered using Boost.Multidimensional.Array?

It looks to adequately address the issue you are trying to solve. You could use it with either Node*, or actual Node types, if that is acceptable for your problem.

Upvotes: 0

Related Questions