Dynamic size matrix using std::vector for storage
suggest changeUnfortunately as of C++14 there’s no dynamic size matrix class in the C++ standard library. Matrix classes that support dynamic size are however available from a number of 3rd party libraries, including the Boost Matrix library (a sub-library within the Boost library).
If you don’t want a dependency on Boost or some other library, then one poor man’s dynamic size matrix in C++ is just like
vector<vector<int>> m( 3, vector<int>( 7 ) );
… where vector
is std::vector
. The matrix is here created by copying a row vector n times where n is the number of rows, here 3. It has the advantage of providing the same m[y]
indexing notation as for a fixed size raw array matrix, but it’s a bit inefficient because it involves a dynamic allocation for each row, and it’s a bit unsafe because it’s possible to inadvertently resize a row.
A more safe and efficient approach is to use a single vector as storage for the matrix, and map the client code’s (x, y) to a corresponding index in that vector:
#include <algorithm> // std::copy
#include <cassert> // assert
#include <initializer_list> // std::initializer_list
#include <vector> // std::vector
#include <cstddef> // ptrdiff_t
// A dynamic size matrix using std::vector for storage.
namespace my {
using Size = ptrdiff_t;
using std::initializer_list;
using std::vector;
template< class Item >
class Matrix
{
private:
vector<Item> items_;
Size n_cols_;
auto index_for( Size const x, Size const y ) const
-> Size
{ return y*n_cols_ + x; }
public:
auto n_rows() const -> Size { return items_.size()/n_cols_; }
auto n_cols() const -> Size { return n_cols_; }
auto item( Size const x, Size const y )
-> Item&
{ return items_[index_for(x, y)]; }
auto item( Size const x, Size const y ) const
-> Item const&
{ return items_[index_for(x, y)]; }
Matrix(): n_cols_( 0 ) {}
Matrix( Size const n_cols, Size const n_rows )
: items_( n_cols*n_rows )
, n_cols_( n_cols )
{}
Matrix( initializer_list< initializer_list<Item> > const& values )
: items_()
, n_cols_( values.size() == 0? 0 : values.begin()->size() )
{
for( auto const& row : values )
{
assert( Size( row.size() ) == n_cols_ );
items_.insert( items_.end(), row.begin(), row.end() );
}
}
};
} // namespace my
//--------------------------------------------- Usage:
using my::Matrix;
auto some_matrix()
-> Matrix<int>
{
return
{
{ 1, 2, 3, 4, 5, 6, 7 },
{ 8, 9, 10, 11, 12, 13, 14 },
{ 15, 16, 17, 18, 19, 20, 21 }
};
}
#include <iostream>
#include <iomanip>
using namespace std;
auto main() -> int
{
Matrix<int> const m = some_matrix();
assert( m.n_cols() == 7 );
assert( m.n_rows() == 3 );
for( int y = 0, y_end = m.n_rows(); y < y_end; ++y )
{
for( int x = 0, x_end = m.n_cols(); x < x_end; ++x )
{
cout << setw( 4 ) << m.item( x, y ); // ← Note: not `m[y][x]`!
}
cout << '\n';
}
}
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
The above code is not industrial grade: it’s designed to show the basic principles, and serve the needs of students learning C++.
For example, one may define operator()
overloads to simplify the indexing notation.