Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nice way to create a dynamic 2D matrix in C++ 11

Tags:

c++

c++11

I already know how to create a dynamic 2D matrix using new and free it using delete. Since C++ 11 is here with many new memory features such as unique_ptr, array container etc.; what is a nice way to create a 2D matrix so that one needs not to free the matrix explicitly using delete operator?

like image 627
aghost Avatar asked Oct 02 '15 21:10

aghost


2 Answers

One of the simplest ways is to use a vector of vectors

const int N = 10;
const int M = 10;
vector<vector<int>> matrix2d(N, vector<int>(M, 0)); // 10x10 zero-initialized matrix
matrix2d[0][0] = 42;

You could of course use a single vector and wrap it into an accessor class

vector<int> matrix(N * M, 0) // Ditto as above, but needs stride-aware accessors

I'll post a small example here for completeness' sake

template <typename T>
class Matrix2D {
    std::vector<T> data;
    unsigned int sizeX, sizeY;
public:
    Matrix2D (unsigned int x, unsigned int y)
        : sizeX (x), sizeY (y) {
        data.resize (sizeX*sizeY);
    }

    T& operator()(unsigned int x, unsigned int y) {
        if (x >= sizeX || y>= sizeY)
            throw std::out_of_range("OOB access"); // Throw something more appropriate
        return data[sizeX*y + x]; // Stride-aware access
    }
};

Live Example

or perhaps combine your way with a smart pointer. Notice that the vector<vector<int>> approach should be used with caution since the vectors are independent from each other and there's nothing to enforce that they should keep their size fixed.

like image 94
Marco A. Avatar answered Sep 23 '22 17:09

Marco A.


I strongly suggest using array_view from the GSL, which will eventually be part of the standard.

#include <array>
#include <vector>
#include "array_view.h" // must be manually imported until standardization

int main()
{
    std::array<int, 10>  arr{}; // 10 ints on the stack
    std::vector<int>  vec{12}; // 12 ints on the heap
    auto a = gsl::array_view<int, 2>{{2, 5}, arr}; // 2D, 2x5 matrix
    auto b = gsl::array_view<int, 3>{{3, 2, 2}, vec}; // 3D, 3x2x2 matrix
    auto c = gsl::array_view<int>{vec}; // 1D, spans from `begin()` to `end()`
    a[{0,3}] += b[{0,1,1}] * -c[2]; // access syntax
}

N.B. array_view holds no control over the lifetime of the range it looks at. See here for full details.

Edit:

array_view is dead as it was becoming too complicated in handling multidimensional arrays with zero cost abstraction. You should instead use span from the GSL.

See this for more information about span.

like image 45
Brian Rodriguez Avatar answered Sep 26 '22 17:09

Brian Rodriguez