I am building an app that needs to have support for two dimensional arrays to hold a grid of data. I have a class Map that contains a 2d grid of data. I want to use vectors rather than arrays, and I was wondering what the best practices were for using 2d vectors. Should I have a vector of vectors of MapCells? or should it be a vector of vectors of pointers to MapCells? or references to MapCells?
class Map {
private:
vector<vector<MapCell>> cells;
public:
void loadMap() {
cells.clear();
for (int i = 0; i < WIDTH; i++) {
//How should I be allocating these?
vector<MapCell> row(HEIGHT);
for (int j = 0; j < HEIGHT; j++) {
//Should I be dynamically allocating these?
MapCell cell;
row.push_back(cell);
}
cells.push_back(row);
}
}
}
Basically what way of doing this is going to get me in the least amount of trouble (with respect to memory management or anything else)?
When you want a square or 2d grid, do something similar to what the compiler does for multidimensional arrays (real ones, not an array of pointers to arrays) and store a single large array which you index correctly.
Example using the Matrix class below:
struct Map {
private:
Matrix<MapCell> cells;
public:
void loadMap() {
Matrix<MapCell> cells (WIDTH, HEIGHT);
for (int i = 0; i < WIDTH; i++) {
for (int j = 0; j < HEIGHT; j++) {
// modify cells[i][j]
}
}
swap(this->cells, cells);
// if there's any problem loading, don't modify this->cells
// Matrix swap guarantees no-throw (because vector swap does)
// which is a common and important aspect of swaps
}
};
Variants of matrix classes abound, and there are many ways to tailor for specific use. Here's an example in less than 100 lines that gets you 80% or more of what you need:
#include <algorithm>
#include <memory>
#include <vector>
template<class T, class A=std::allocator<T> >
struct Matrix {
typedef T value_type;
typedef std::vector<value_type, A> Container;
Matrix() : _b(0) {}
Matrix(int a, int b, value_type const& initial=value_type())
: _b(0)
{
resize(a, b, initial);
}
Matrix(Matrix const& other)
: _data(other._data), _b(other._b)
{}
Matrix& operator=(Matrix copy) {
swap(*this, copy);
return *this;
}
bool empty() const { return _data.empty(); }
void clear() { _data.clear(); _b = 0; }
int dim_a() const { return _b ? _data.size() / _b : 0; }
int dim_b() const { return _b; }
value_type* operator[](int a) {
return &_data[a * _b];
}
value_type const* operator[](int a) const {
return &_data[a * _b];
}
void resize(int a, int b, value_type const& initial=value_type()) {
if (a == 0) {
b = 0;
}
_data.resize(a * b, initial);
_b = b;
}
friend void swap(Matrix& a, Matrix& b) {
using std::swap;
swap(a._data, b._data);
swap(a._b, b._b);
}
template<class Stream>
friend Stream& operator<<(Stream& s, Matrix const& value) {
s << "<Matrix at " << &value << " dimensions "
<< value.dim_a() << 'x' << value.dim_b();
if (!value.empty()) {
bool first = true;
typedef typename Container::const_iterator Iter;
Iter i = value._data.begin(), end = value._data.end();
while (i != end) {
s << (first ? " [[" : "], [");
first = false;
s << *i;
++i;
for (int b = value._b - 1; b; --b) {
s << ", " << *i;
++i;
}
}
s << "]]";
}
s << '>';
return s;
}
private:
Container _data;
int _b;
};
If the whole matrix has a mostly constant width and height, you may as well use a single vector, and address cells with (row * columnCount) + column. That way the whole thing will be stored in a single memory block instead of in several fragmented blocks for each row. (Though of course you are doing the right thing to wrap this concept up in a new class - I'm just talking about the behind-the-scenes implementation.)
A vector of vectors has the unfortunate property that if you insert a row at the top, std::vector will perform a copy construction (or assignment, possibly) for all the other rows as it shifts them down by one place. This in turn involves reallocating the storage for every row and individually copying the items in the cells of every row. (C++0x will probably be better at this.)
If you know that you will be doing that kind of thing often, the advantage of a single large memory block is that you can insert a new row at the top and std::vector will only have to shift all the cells forward by columnCount places, so it will seriously reduce the number of heap operations (freeing/reallocating of individual blocks).
Although as you suggest, a vector of pointers to vectors would have the further advantage that it would only need to shift forward a lot of pointer values, and the size of the block containing all the row pointers will be much smaller, further lessening the impact of heap operations.
Of course, the only way to be sure of the actual impact of these things on the performance of an application is to time it with various implementations and compare them. This is why you're doing exactly the right thing by hiding these details inside a new class.
Use a vector and translate the 2 dimensions to one dimension.
E.g. if your matrix has a width of W and a height of H, then mapping x,y to the index in the vector is simply x*W+y.
If your matrix is sparse you may want to use an std::map where the key is a pair (x and y).
In my projects I often use this simple grid class.
Related
I'm a high school student learning programming and I have a problem that I can't figure out how to solve.
I have an integer "x", and I want a matrix "mat" to have the size of "x":
int mat[x][x];
But that works only in main() where I've read x;
For example if x == 5, the equivalent would be
int mat[5][5];
#include <iostream>
using namespace std;
int x;
int mat[x][x];
void f(int mat2[x][x])
{
}
int main()
{
cin >> x;
int m[x][x];
f(m);
}
I've wrote this short program to show where it works and it doesn't work.
error: array bound is not an integer constant before ']' token
I've the error at the global declaration, at the declaration in function void f. It only compiles without errors in main();
What can I do to create a matrix with the size of x outside of the main function?
Variable length arrays aren't spported in standard c++. Besides you don't want the global definition.
What you can use portably in that case is std::vector:
void f(std::vector<std::vector<int>>& mat)
{
}
int main()
{
cin >> x;
std::vector<std::vector<int>> m(x,std::vector<int>(x));
f(m);
}
If you pass that vector around to functions or being allocated within functions, the size information will be kept at any time.
What can I do to create a matrix with the size of x outside of the main function?
Something like this:
std::vector<std::vector<int>> foo() {
cin >> x;
std::vector<std::vector<int>> m(x,std::vector<int>(x));
return m;
}
int main()
{
std::vector<std::vector<int>> mat = foo();
}
Handling of multi-dimension arrays in C++ is not easy. The best way to go is often to map a multi-dimensionnal indexing with a linear memory chunk.
For instance, for a 2 by 2 matrix, one can create an array of 2*2=4 elements and map it this way:
+-----------+-----------+-----------+-----------+
| map[0][0] | map[0][1] | map[1][0] | map[1][1] |
+-----------+-----------+-----------+-----------+
This seems overly complicated at first glance, but it simplifies greatly the memory allocation.
For an arbitrary sized matrix of width by height, map[i][j] is at index i*height + j. This can be translated in C++, encapsulated in a template class Matrix:
#include <array>
template <typename T, size_t WIDTH, size_t HEIGHT>
class Matrix {
std::array<T, WIDTH*HEIGHT> data;
public:
T& operator()(size_t i, size_t j) {
return data[i*HEIGHT + j];
}
const T& operator()(size_t i, size_t j) const {
return data[i*HEIGHT + j];
}
};
This has the disadvantage that the Matrix' dimensions must be known at compile time (and can be mitigated, see note (ii) at end of answer). But it makes its use so easy:
void fill(Matrix<int, 2, 2>& m) {
m(0,0) = 0;
m(0,1) = 1;
m(1,0) = 2;
m(1,1) = 3;
}
int main() {
Matrix<int, 2, 2> m;
fill(m);
std::cout << m(1,0) << "\n";
}
Note (i): Elements are indexed by (line, column) rather than [line][column] because we can't create an operator[] accepting multiple values.
Live on coliru
Note (ii): This basic idea can be enriched (demo) to handle resizable matrixes, with use of a std::vector instead of std::array and a proxy to std::vector::resize().
Variable-length array is supported by some compiler as an extension. The manual of the compiler provides more information.Gnu VLR
The storage duration of a variable-length array(if supported) generally can't be static, which is why you get the error message (global variables have static storage duration).
Unrelated: The major array bound of the parameter mat2 isn't necessary, i.e. void f(int mat2[x][x]) is equivalent to void f(int mat2[][x]).
C++ has no provision for dynamic 2D matrix but provides all you need to create complex classes. A (static) 2D array is a contiguously allocated array of height arrays of width elements. Just mimic that and:
allocate a linear array of width * height
provide an operator[](int) that returns a pointer to the first element of ith row
do necessary housekeeping in destructor and in a copy (and move if C++11 or above) constructor.
Example of code:
template <typename T>
class Matrix {
T *data;
int width;
int height;
public:
// direct ctor
Matrix(int h, int w): width(w), height(h) {
data = new T[w * h];
}
//copy ctor
Matrix(const Matrix& src): width(src.width), height(src.height) {
data = new T[width * height]; // allocate and copy data array
for (int i=0; i<width * height; i++) data[i] = src.data[i];
}
// move ctor
Matrix(Matrix&& src): width(src.width), height(src.height) {
data = src.data; // steal original array in a move
src.data = NULL; // ensure no deletion will occur at src destruction
}
~Matrix() {
delete data;
data = NULL;
}
// explicitely delete assignement operators
Matrix& operator = (const Matrix&) = delete;
Matrix& operator = (Matrix&&) = delete;
T* operator[](int i) {
//optionaly test 0 <= i < width
return &data[i * width];
}
};
int main()
{
int w;
std::cin >> x;
Matrix<int> m(x, x);
// you can then use m[i][j] as you would for a static 2D array
...
}
This class does not support any resizing by design. If you need that, you really should use a vector<vector<T> >. The downside is that it has no default ctor either, because the dimension must be given at definition time (even if we could easily imagine a 2 phases initialization...).
You can dynamic allocate memory to use, in the c/c++, it does not support dynamic size of static memory allocation, so, you just modify your code like this.
int x;
cin >>x;
int** mat = new int[x][x];
I am new to C++ which is the reason why I'm currently kind of stuck.
Now here's the Problem: I have a couple of float matrices like this:
static const float matr1[4][8] = {0.0, 0.0, ...};
static const float matr2[7][8] = {0.0, 0.5, ...};
etc.
I have a struct like to this one:
struct structy{
float matr[][];
int index;
float somevalue;
};
I have a vector of this structy which is created dynamically dependent on other information.
How can I reference a certain of these declared matrices in my struct variable, given that the first parameter of the struct (rows) varies?
I need a row of the matrices as a float array later on.
Thanks for your help!
You should also store the number of columns and the number of rows in structy, so that you know the dimensions of matr at a later point in time. There is no way to check the length of the 2D array otherwise.
As for your main question: Are you having troubles accessing individual matrix entries in one of your 2D float arrays (matr)?
The only way I have ever seen this done is dynamically:
struct structy{
float ** matr;
// Need to add these 2 variables
int dimensionRow;
int dimensionCol;
int index;
float somevalue;
};
When you place the data into matr, you need to also set dimensionRow, and dimensionCol, as well as dynamically allocate matr prior to filling it, IFF you plan to copy. If not you can simply set matr to the pointer of one of your pre-defined matrices. Either way you will need to also set dimensionRow and dimensionCol.
If you need varying sized matrices, I'd suggest using a vector of vectors. This will save you from the trouble of manually allocating a 2D array and managing its memory. One possible implementation:
struct structy {
std::vector< std::vector<float> > matr;
int index;
float somevalue;
};
structy s;
...
s.matr[0][1] = 42.0f;
...
And either grow the vectors on demand using push_back() or grow them beforehand with resize().
Now if you just want a reference to an external matrix (pointer to static memory) then you can just declare a pointer to pointer (double pointer):
struct structy {
const float ** matr;
int index;
float somevalue;
};
You cannot create a reference (not in the traditional sense) that will refer to different types, and arrays with different lengths are different types. However, you can take advantage of the fact that arrays are contiguous, (and so arrays of arrays are contiguous arrays), and create a class that acts as a reference using pointers.
template<typename T>
class matrix_reference
{
public:
template<size_t R, size_t C>
void set_reference(T (&arr)[R][C])
{
m_start = &arr[0][0];
m_rows = R;
m_columns = C;
}
T& operator()(size_t r, size_t c)
{
return m_start[r * m_columns + c];
}
size_t rows() const { return m_rows; }
size_t columns() const { return m_columns; }
private:
T* m_start;
size_t m_rows;
size_t m_columns;
};
int main()
{
matrix_reference<const float> mref;
mref.set_reference(matr1);
for (size_t r=0; r<mref.rows(); ++r)
{
for (size_t c=0; c<mref.columns; ++c)
std::cout << mref(r,c) << ' ';
std::cout << '\n';
}
mref.set_reference(matr2);
for (size_t r=0; r<mref.rows(); ++r)
{
for (size_t c=0; c<mref.columns; ++c)
std::cout << mref(r,c) << ' ';
std::cout << '\n';
}
}
Annoyance over C++'s requirement to pass a dimension in a 2-d array got me working on a templated Matrix class. I've been coding in C# for a bit, so I'm sure I'm a little rusty here.
Issue is, I get a heap exception as soon as I hit the destructor, which is trying to delete the 2-d array.
Any help gratefully accepted!
template <typename T>
class Matrix {
public:
Matrix(int m, int n) : nRows(m), nCols(n) {
pMatrix = new T * [nRows];
for (int i = 0; i < nCols; i++) {
pMatrix[i] = new T[nCols];
}
}
~Matrix() {
if (pMatrix != NULL) {
for (int i = 0; i < nRows; i++) { delete[] pMatrix[i]; }
delete[] pMatrix;
}
}
T ** GetMatrix() const { return pMatrix; }
T * Row(int i) const { return pMatrix[i]; }
inline T Cell(int row, int col) const { return pMatrix[row][col]; }
inline int GetNRows() const { return nRows; }
inline int GetNCols() const { return nCols; }
private:
int nRows, nCols;
T ** pMatrix;
};
This is the bug:
for (int i = 0; i < nCols; i++) {
pMatrix[i] = new T[nCols];
}
The loop should be until nRows, not nCols.
Other than that, let me tell you about something I did when I got tired of allocating 2-d arrays. I had to do a 3-d array. I used a map, that mapped from a coordinate - a struct holding x, y, z to the type I wanted.
I worked fast, and no need to allocate or deallocate. Assigning to a coordinate was simply done by
mymap[Coord(x, y, z)] = whatever...
Of course I needed to define the Coord struct and overload the < operator, but I found that way more comvenient than trying to allocate and deallocate a 3-d array.
Of course you will need to check if this scheme is fast enough for you. I used it to draw cells within a big cube using OpenGL and had no complaints at all.
Concerning the bug, #CodeChords_man explained it right. I have notes on implementation. I recommend to look through this wonderful FAQ post.
You should not use dynamic memory allocation unless you are 100% sure that
You really need it
You know how to implement it
I don't know of the first, and how the performance is crucial for you. But as for the second, you at least violated the rule of three. You class is very unsafe to use. If you copy it, the memory buffer will then be double-deleted.
You should not afraid to used STL containers, they are fast and optimized. At least the std::vector, it is as fast as the raw pointer in many scenarios. You can rewrite you class using std::vector as follows:
template <typename T>
class Matrix {
public:
typedef std::vector<T> MatrixRow;
typedef std::vector<MatrixRow> MatrixBody;
Matrix(int m, int n) : nRows(m), nCols(n), _body(m, MatrixRow(n)) {}
const MatrixBody& GetMatrix() const { return _body; }
const MatrixRow& GetRow(int i) const { return _body[i]; }
inline T Cell(int row, int col) const { return _body[row][col]; }
inline int GetNRows() const { return nRows; }
inline int GetNCols() const { return nCols; }
private:
int nRows, nCols;
MatrixBody _body;
};
Since this class is not using dynamic memory allocation, it is safe to copy and assign. You also don't need to explicitly store nRows and nCols in this case; you can use _body.size() and _body[0].size() instead.
Concerning underlying vector of vectors, it is dereferenced using the same [i][j] construction. It is easily iterated with begin() and end(). And if you absolutely need to use the raw pointer in some routine, you can always access it with &row[0].
The only possible difficulty is that you cannot easily convert MatrixBody to T**. But think it twice, maybe you don't really need to use T** at all.
I need to dynamically allocate 1-D and 2-D arrays whose sizes are given at run-time.
I managed to "discover" std::vector and I think it fits my purposes, but I would like to ask whether what I've written is correct and/or can be improved.
This is what I'm doing:
#include <vector>
typedef std::vector< std::vector<double> > matrix;
//... various code and other stuff
std::vector<double> *name = new std::vector<double> (size);
matrix *name2 = new matrix(sizeX, std::vector<double>(sizeY));
Dynamically allocating arrays is required when your dimensions are given at runtime, as you've discovered.
However, std::vector is already a wrapper around this process, so dynamically allocating vectors is like a double positive. It's redundant.
Just write (C++98):
#include <vector>
typedef std::vector< std::vector<double> > matrix;
matrix name(sizeX, std::vector<double>(sizeY));
or (C++11 and later):
#include <vector>
using matrix = std::vector<std::vector<double>>;
matrix name(sizeX, std::vector<double>(sizeY));
You're conflating two issues, dynamic allocation and resizable containers. You don't need to worry about dynamic allocation, since your container does that for you already, so just say it like this:
matrix name(sizeX, std::vector<double>(sizeY));
This will make name an object with automatic storage duration, and you can access its members via name[i][j].
What you're doing should basically work, however:
In general, don't dynamically allocate objects
If you want a vector, do this:
std::vector<double> vec(size);
not this:
std::vector<double>* vec = new std::vector<double>(size);
The latter gives you a pointer, which you have to delete. The former gives you a vector which, when it goes out of scope, cleans up after itself. (Internally, of course, it dynamically allocates objects, but the trick is that this is handled by the class itself, and you don't need to worry about it in your user code).
It is correct but could be made more efficient.
You could use the boost multidimensional arrays:
http://www.boost.org/doc/libs/1_47_0/libs/multi_array/doc/user.html
Or, you can implement your own class for it and handle the indexing yourself.
Perhaps something like this (which is not well tested):
#include <vector>
#include <cassert>
template <typename T, typename A = std::allocator<T> >
class Array2d
{
public:
typedef Array2d<T> self;
typedef std::vector<T, A> Storage;
typedef typename Storage::iterator iterator;
typedef typename Storage::const_iterator const_iterator;
Array2d() : major_(0), minor_(0) {}
Array2d(size_t major, size_t minor)
: major_(major)
, minor_(minor)
, storage_(major * minor)
{}
template <typename U>
Array2d(size_t major, size_t minor, U const& init)
: major_(major)
, minor_(minor)
, storage_(major * minor, u)
{
}
iterator begin() { return storage_.begin(); }
const_iterator begin() const { return storage_.begin(); }
iterator end() { return storage_.end(); }
const_iterator end() const { return storage_.end(); }
iterator begin(size_t major) {
assert(major < major_);
return storage_.begin() + (major * minor_);
}
const_iterator begin(size_t major) const {
assert(major < major_);
return storage_.begin() + (major * minor_);
}
iterator end(size_t major) {
assert(major < major_);
return storage_.begin() + ((major + 1) * minor_);
}
const_iterator end(size_t major) const {
assert(major < major_);
return storage_.begin() + ((major + 1) * minor_);
}
void clear() {
storage_.clear();
major_ = 0;
minor_ = 0;
}
void clearResize(size_t major, size_t minor)
{
clear();
storage_.resize(major * minor);
major_ = major;
minor_ = minor;
}
void resize(size_t major, size_t minor)
{
if ((major != major_) && (minor != minor_))
{
Array2d tmp(major, minor);
swap(tmp);
// Get minimum minor axis
size_t const dist = (tmp.minor_ < minor_) ? tmp.minor_ : minor_;
size_t m = 0;
// copy values across
for (; (m < tmp.major_) && (m < major_); ++m) {
std::copy(tmp.begin(m), tmp.begin(m) + dist, begin(m));
}
}
}
void swap(self& other)
{
storage_.swap(other.storage_);
std::swap(major_, other.major_);
std::swap(minor_, other.minor_);
}
size_t minor() const {
return minor_;
}
size_t major() const {
return major_;
}
T* buffer() { return &storage_[0]; }
T const* buffer() const { return &storage_[0]; }
bool empty() const {
return storage_.empty();
}
template <typename ArrRef, typename Ref>
class MajorProxy
{
ArrRef arr_;
size_t major_;
public:
MajorProxy(ArrRef arr, size_t major)
: arr_(arr)
, major_(major)
{}
Ref operator[](size_t index) const {
assert(index < arr_.minor());
return *(arr_.buffer() + (index + (major_ * arr_.minor())));
}
};
MajorProxy<self&, T&>
operator[](size_t major) {
return MajorProxy<self&, T&>(*this, major);
}
MajorProxy<self const&, T const&>
operator[](size_t major) const {
return MajorProxy<self&, T&>(*this, major);
}
private:
size_t major_;
size_t minor_;
Storage storage_;
};
While the points the other answers made were very correct (don't dynamically allocate the vector via new, but rather let the vector do the allocation), if you are thinking terms of vectors and matrices (e.g. linear algebra), you might want to consider using the Eigen matrix library.
You don't allocate containers dynamically. They can automatically manage memory for you if they themselves are not manually managed.
A vector grows when you add new items with push_back (or insert), you can choose its size from the start with arguments to the constructor, and you can resize it later with the resize method.
Creating a vector of vectors with your sizes with the constructor looks like this:
std::vector< std::vector<double> > matrix(size, std::vector<double>(sizeY));
This means: size instances of a std::vector<double>, each containing sizeY doubles (initialized to 0.0).
Sometimes you don't want to fill your stack and your memory requirement is large. Hence you may want to use vector> created dynamically especially while creating a table of a given row and col values.
Here is my take on this in C++11
int main() {
int row, col;
std::cin >> row >> col;
auto *arr = new std::vector<std::vector<int>*>(row);
for (int i=0; i<row; i++) {
auto *x = new std::vector<int>(col, 5);
(*arr)[i] = x;
}
for (int i=0; i<row; i++) {
for(int j=0; j<col; j++) {
std::cout << arr->at(i)->at(j) << " ";
}
std::cout << std::endl;
}
return 0;
}
#include < iostream >
#include < vector >
using namespace std;
int main(){
vector<int>*v = new vector<int>(); // for 1d vector just copy paste it
v->push_back(5);
v->push_back(10);
v->push_back(20);
v->push_back(25);
for(int i=0;i<v->size();i++){
cout<<v->at(i)<<" ";
}
cout<<endl;
delete v;
system("pause");
return 0;
}
If you don't need to resize the array sizes at run time, then you can just use standard arrays (allocated at runtime)!
However, if you do need to resize arrays at runtime, then you can use the following (revised) code:
#include <vector>
typedef std::vector< std::vector<double> > matrix;
//... various code and other stuff
std::vector<double> *name = new std::vector<double> (size);
matrix *name2 = new matrix(sizeX, std::vector<double>(sizeY));
In essence, all I've done is remove a single bracket (().
In C, if I wanted to create a matrix struct, I would use:
struct matrix {
int col, row;
double data[1]; // I want the matrix entries stored
// right after this struct
}
Then I can allocate it with
matrix* allocate_matrix(int row, int col) {
matrix* m = malloc(sizeof(matrix) + sizeof(double) * (row * col - 1));
m->row = row; m->col = col;
return m;
}
Now do I do the equiv in C++?
EDIT:
I want to know the cannonical way to implement a matrix class in C++.
nota bene.
This answer has 20 upvotes now, but it is not intended as an endorsement of std::valarray.
In my experience, time is better spent installing and learning to use a full-fledged math library such as Eigen. Valarray has fewer features than the competition, but it isn't more efficient or particularly easier to use.
If you only need a little bit of linear algebra, and you are dead-set against adding anything to your toolchain, then maybe valarray would fit. But, being stuck unable to express the mathematically correct solution to your problem is a very bad position to be in. Math is relentless and unforgiving. Use the right tool for the job.
The standard library provides std::valarray<double>. std::vector<>, suggested by a few others here, is intended as a general-purpose container for objects. valarray, lesser known because it is more specialized (not using "specialized" as the C++ term), has several advantages:
It does not allocate extra space. A vector rounds up to the nearest power of two when allocating, so you can resize it without reallocating every time. (You can still resize a valarray; it's just still as expensive as realloc().)
You may slice it to access rows and columns easily.
Arithmetic operators work as you would expect.
Of course, the advantage over using C is that you don't need to manage memory. The dimensions can reside on the stack, or in a slice object.
std::valarray<double> matrix( row * col ); // no more, no less, than a matrix
matrix[ std::slice( 2, col, row ) ] = pi; // set third column to pi
matrix[ std::slice( 3*row, row, 1 ) ] = e; // set fourth row to e
C++ is mostly a superset of C. You can continue doing what you were doing.
That said, in C++, what you ought to do is to define a proper Matrix class that manages its own memory. It could, for example be backed by an internal std::vector, and you could override operator[] or operator() to index into the vector appropriately (for example, see: How do I create a subscript operator for a Matrix class? from the C++ FAQ).
To get you started:
class Matrix
{
public:
Matrix(size_t rows, size_t cols);
double& operator()(size_t i, size_t j);
double operator()(size_t i, size_t j) const;
private:
size_t mRows;
size_t mCols;
std::vector<double> mData;
};
Matrix::Matrix(size_t rows, size_t cols)
: mRows(rows),
mCols(cols),
mData(rows * cols)
{
}
double& Matrix::operator()(size_t i, size_t j)
{
return mData[i * mCols + j];
}
double Matrix::operator()(size_t i, size_t j) const
{
return mData[i * mCols + j];
}
(Note that the above doesn't do any bounds-checking, and I leave it as an exercise to template it so that it works for things other than double.)
You could do it that way. The only difference is you'd need to cast the result from malloc.
Rather, you would use a vector, either as a 1D array with computed indexing or an embedded vector. (The former matches your code better.)
For example:
template <typename T> // often, they are templates
struct matrix
{
// should probably be hidden away, and the class would
// provide `at` and `operator()` for access
int col, row;
std::vector<T> data;
matrix(int columns, int rows) :
col(columns), row(rows),
data(col * row)
{}
}
matrix m(4, 4);
m.data[1 + 1 * 4] = /* ... */;
Or:
template <typename T>
struct matrix
{
int col, row;
std::vector<std::vector<T> > data;
matrix(int columns, int rows) :
col(columns), row(rows),
data(col, std::vector(row))
{}
}
matrix m(4, 4);
m.data[1][1] = /* ... */;
But these are only examples. You'd want to make a full-fledged class; if you want more advice on that, edit your question and clarify you'd like to know the canonical way of implementing matrix classes.
There are pre-existing matrix classes. My favorite is that from boost, UBLAS.
There's lots of subtleties in setting up an efficient and high quality matrix class. Thankfully there's several good implementations floating about.
Think hard about whether you want a fixed size matrix class or a variable sized one.
i.e. can you do this:
// These tend to be fast and allocated on the stack.
matrix<3,3> M;
or do you need to be able to do this
// These tend to be slower but more flexible and partially allocated on the heap
matrix M(3,3);
There's good libraries that support either style, and some that support both.
They have different allocation patterns and different performances.
If you want to code it yourself, then the template version requires some knowledge of templates (duh). And the dynamic one needs some hacks to get around lots of small allocations if used inside tight loops.
You could use a template like :
#include <iostream>
using std::cerr;
using std::endl;
//qt4type
typedef unsigned int quint32;
template <typename T>
void deletep(T &) {}
template <typename T>
void deletep(T* & ptr) {
delete ptr;
ptr = 0;
}
template<typename T>
class Matrix {
public:
typedef T value_type;
Matrix() : _cols(0), _rows(0), _data(new T[0]), auto_delete(true) {};
Matrix(quint32 rows, quint32 cols, bool auto_del = true);
bool exists(quint32 row, quint32 col) const;
T & operator()(quint32 row, quint32 col);
T operator()(quint32 row, quint32 col) const;
virtual ~Matrix();
int size() const { return _rows * _cols; }
int rows() const { return _rows; }
int cols() const { return _cols; }
private:
Matrix(const Matrix &);
quint32 _rows, _cols;
mutable T * _data;
const bool auto_delete;
};
template<typename T>
Matrix<T>::Matrix(quint32 rows, quint32 cols, bool auto_del) : _rows(rows), _cols(cols), auto_delete(auto_del) {
_data = new T[rows * cols];
}
template<typename T>
inline T & Matrix<T>::operator()(quint32 row, quint32 col) {
return _data[_cols * row + col];
}
template<typename T>
inline T Matrix<T>::operator()(quint32 row, quint32 col) const {
return _data[_cols * row + col];
}
template<typename T>
bool Matrix<T>::exists(quint32 row, quint32 col) const {
return (row < _rows && col < _cols);
}
template<typename T>
Matrix<T>::~Matrix() {
if(auto_delete){
for(int i = 0, c = size(); i < c; ++i){
//will do nothing if T isn't a pointer
deletep(_data[i]);
}
}
delete [] _data;
}
int main() {
Matrix< int > m(10,10);
quint32 i = 0;
for(int x = 0; x < 10; ++x) {
for(int y = 0; y < 10; ++y, ++i) {
m(x, y) = i;
}
}
for(int x = 0; x < 10; ++x) {
for(int y = 0; y < 10; ++y) {
cerr << "#(" << x << ", " << y << ") : " << m(x,y) << endl;
}
}
}
*edit, fixed a typo.
you could do it with a template, if the matrix size is known at compile-time :
template <int width, int height>
class Matrix{
double data[height][width];
//...member functions
};
For a matrix class, you want to stay away from overloading the [] operator.
See C++ FAQ 13.10
Also, search the web for some freeware Matrix classes. Worst case, they can give you guidance. Best case, less software that you have to write and debug.
There is no "canonical" way to do the matrix in C++, STL does not provide classes like "matrix". However there are some 3rd party libraries that do. You are encouraged to use them or write your own implementation. You can try my implementation derived from some public implementation found on the internet.
The library called, Matrix supports so many features including mathematics operations, dumping and logging features, associative containers, multiple dimensions and etc.
Usage
its usage is similar to c++ arrays.
Matrix<int> A(1, 2);
Matrix<int> B(2, 3);
Matrix<int> result(1, 3);
A[0][0] = 7;
A[0][1] = 10;
B[0][0] = 1;
B[0][1] = 4;
B[0][2] = 2;
B[1][0] = 1;
B[1][1] = 2;
B[1][2] = 100;
result = A * B;
result.dump.matrix();
Result:
Matrix view:
- -
| 17 48 1014 |
- -
Here is the documentation and Github page.
In C++ you can use like this:
matrix *p = new matrix;
After that,
delete p;