MyNameIsKhan
MyNameIsKhan

Reputation: 2612

How to make a dynamically-sized double-int array?

I am trying to make a generic matrix struct in C++ but right now all I've got is

struct matrix{
    int cells[dim][dim];
}

where dim is a const int.

However I wish to make things a little more dynamic so I can declare matrices of different sizes. I can get around this issue by converting everything to vectors of int vectors, but then I suffer a massive speed loss.

Upvotes: 2

Views: 199

Answers (3)

quadruplebond
quadruplebond

Reputation: 43

You can also use a single vector for matrix class which works pretty well since the data will be sequential depending on row or column based storage. For example

Struct Matrix {
    std::vector<int> cells;
    int nrows, ncols;

    Matrix(int rows, int cols) : cells(rows * cols), nrows(rows), ncols(cols) 
    {}

    int& operator()(int row, int col){
        return cells[row * ncols + col];
    }

    void resize(int rows, int cols){
        cells.resize(rows*cols);
        nrows = rows; 
        ncols = cols;
    }
}

This is a nice vector wrapper for a matrix that avoids you needing to use c-style things.

Upvotes: 2

sehe
sehe

Reputation: 393084

FWIW I'd always go with a flat vector (pre-reserved/sized) or Boost MultiArray.

However, what's wrong with a template?

template<typename T, size_t N, size_t M=N>
struct matrix {
    typedef T row_type[M];
    row_type cells[N];

    row_type*       begin()       { return std::begin(cells); }
    row_type*       end()         { return std::end(cells);   }
    row_type const* begin() const { return std::begin(cells); }
    row_type const* end()   const { return std::end(cells);   }
};

Or even better, with std::array:

#include <array>

template<typename T, size_t N, size_t M=N>
struct matrix {
    typedef std::array<T, M> row_type;
    std::array<row_type, N> cells;

    row_type*       begin()       { return cells.begin(); }
    row_type*       end()         { return cells.end();   }
    row_type const* begin() const { return cells.begin(); }
    row_type const* end()   const { return cells.end();   }
};

Just a cheesy demo to show it's genericity: Live on Coliru

#include <algorithm>

template<size_t N, typename T=int>
T test()
{
    using std::begin;
    using std::end;
    typedef matrix<T, N, N*3+2> Mtx;
    Mtx the_matrix;

    size_t next_gen {};
    auto gen = [&](){ return next_gen++ * 3.14; };

    for(auto& row : the_matrix)
        std::generate(begin(row), end(row), gen);

    return std::accumulate(
            begin(the_matrix), end(the_matrix), T{},  
            [](T accum, typename Mtx::row_type& row) 
            { 
                return accum + std::accumulate(begin(row), end(row), T{}); 
            });
}

#include <iostream>
#include <string>

int main()
{
    std::cout << test<3, int>()    << "\n";
    std::cout << test<3, double>() << "\n";
}

Upvotes: 1

user529758
user529758

Reputation:

I can get around this issue by converting everything to vectors of int vectors, but then I suffer a massive speed loss.

FAUX. That's just wrong. std::vector is almost as fast as raw arrays. Do use vector<vector<int> >.


However, if you still insist on raw arrays:

int **p = new int *[rows];
for (size_t i = 0; i < rows; i++)
    p[i] = new int[columns];

Freeing:

for (size_t i = 0; i < rows; i++)
    delete [] p[i];

delete [] p;

Upvotes: 0

Related Questions