How to initialize a 2D array in a class? - c++

I have a Matrix class that looks something like this:
template<int R, int C>
class Matrix{
public:
double matrix[R][C];
Matrix(double n = 0)...{}
...
};
Matrix<2,3> m;
How do I initialize the array when creating a new matrix with the n in the c'tor, without iterating over the whole array cell by cell?
I've read here some answers about something called memset, but I can't use it at the moment (it's a part of homework assignment).

My advice is to use std algorithms wherever possible:
std::for_each(std::begin(matrix), std::end(matrix),
[n](double* row) { std::fill_n(row, C, n); } );
Full example:
template<int R, int C>
class Matrix{
public:
double matrix[R][C];
Matrix(double n = 0) {
std::for_each(std::begin(matrix), std::end(matrix),
[n](double* row) { std::fill_n(row, C, n); } );
}
};

Iterate over the whole array cell be cell using clear, simple, obvious code. If your compiler is sensible (and why use it if it's not) it will understand precisely what you are doing and substitute in the optimal initialization mechanism for your platform.

Related

unable to create 2d matrix inside a class

The error is : "member matrix::rows is not a type name" and "member matrix::init is not a type name". If it compiles successfully I shall have a matrix rows = ROWS and columns = COLS. What am i doing wrong here:
#include <vector>
class matrix
{
int ROWS{}, COLS{}, init{-1};
std::vector<std::vector<int>> table(ROWS, std::vector<int>(COLS, init));
};
As John Zwinck points out, you need curly brackets. Why? Because, otherwise, the compiler takes
std::vector<std::vector<int>> table(ROWS, std::vector<int>(COLS, init));
as the definition of a member function, called table, returning a std::vector<std::vector<int>> and taking a first (unnamed) parameter of type ROWS. At which point the compiler goes "Ugh, I don't know the type ROWS, let me throw a compilation error".
You can google Most Vexing Parse. https://en.wikipedia.org/wiki/Most_vexing_parse
You can write it like this:
class matrix
{
static constexpr int ROWS{}; // TODO: change to non-zero
static constexpr int COLS{}; // TODO: change to non-zero
static constexpr int init{-1};
std::vector<std::vector<int>> table{ROWS, std::vector<int>(COLS, init)};
};
I don't understand the usage of the vector of vectors for this case.
For such a case, I would propose to use a plain array.
template<int N, int M, typename D> struct Matrix {
public:
D get(int i, int j) {
return _data[index(i,j)];
}
void set(int i, int j, D v) {
_data[index(i,j)] = v;
}
private:
int index(int i, int j){
return i*N + j;
}
D _data[N*M];
};
So you don't really need std::vector. Just add some checks and you are good.

c++, Object of class changes when creating a new object

I have created a class matrix that besides having some member functions, operators and a constructor has two variables:
int m, which is the dimension (side length) of the quadratic matrix
double a[], which contains the elements of the matrix.
As long as I only create one matrix object A all seem to work fine and all my member operators and functions work as they should.
My problem is that once I create a second object B of the class matrix the variables of object A changes as well.
The relevant code is as follows:
class Matrix{
private:
const int m;
double a[];
public:
Matrix(int inpm);
void fillMatrix(const double inpa[]);
};
Matrix::Matrix(int inpm): m(inpm){
a[impm*inpm];
}
void Matrix::fillmatrix(const double inpa[]){
for (int i ; i<m*m ; i++){
a[i]=inpa[i];
}
}
int min =2;
double ain[min*min] = {1,2,3,4};
double bin[min*min] = {5,6,7,8};
Matrix A(min);
Matrix B(min);
A.fillMatrix(ain);
//A looks precisely as it should here:
//m=2, a={1,2,3,4}
B.fillMatrix(bin);
//Here B looks as it should but A has changed to:
//m=0, a={7,8,3,4}
obviously the change to the first object occur when I run fillMatrix() for the second object but I cannot figure out why, especially since m is a constant integer.
I'm really stuck so grateful for all help.
PS: I use another member function "void printMatrix();" using std:cout to look at the values of m and all elements in a.
a[impm*inpm]; This does not do what you think. GCC even warns with statement has no effect.
a remains uninitialized here and you run into undefined behavior when you try to access a[i]
class Matrix{
private:
const int m;
double *a;
....
and
Matrix::Matrix(int inpm): m(inpm)
{
a = new double[inpm*inpm];
}
and then remember to delete
Matrix::~Matrix()
{
delete a;
}
c++ arrays are not actually allowed to variable. There are plenty of sources about why variable length arrays (vla's) are not allowed. If you wan't a dynamic length array with size chosen at run time, you need to allocate some memory:
double *a;
...
a = new double[inpm*inpm];
But this sucks! Now you have to remember to delete and access correctly and everything. You could wrap this memory in a class to control this, and since this is such a good idea, c++ provides this as standard. It is called std::vector. Your code will happily reduce to this:
class Matrix{
private:
const int m;
std::vector<double> a;
public:
Matrix(int inpm) : m(inpm), a(m * m) {}
The problem is because of your array declaration. people used to call that kind of array declaration as "flexible array declaration.". And it wouldn't work as you expected. plus there are certain rules to follow while using a flexible array.
But if you want to create a dynamic array you can use malloc to create array dynamically.
I've noticed a few issues with your code. The first few were already mentioned by others such as your member double a[]; This is uninitialized and C++ does not allow for variable length vectors. To resolve this there are two possible solutions which I'll discuss shortly. The other issue that others have mentioned is that in your Matrix::fillMatrix() function the variable in your for loop i is also uninitialized, so i can be anything and this will lead to undefined behavior.
A few issues that have not been mentioned by others are as follows:
In your constructor definition you are trying to initialize m with a[impm*inpm] I think this might be a typo on your part. Another one is you declare your function as ::fillMatrix() but you define it outside of the class declaration as ::fillmatrix(). Again I think this might be just a typo on your part.
As for the issue above with the use of arrays in C++ the easiest way to do this is what others have already stated and that is to use std::vector<type>.
The other way is to write a class that works similarly to std::vector but has the mechanics of a matrix. Your class would look something like this using templates: If you want a variable length container at runtime you have to know it's size at compile time using templates here can help as the template has to be deduced at compile time upon instantiation!
template<class T, unsigned N>
class Matrix {
private:
static const unsigned Stride = N;
static const unsigned Size = Stride * Stride;
T data[Size] = {};
public:
Matrix() {};
void fillMatrix( const T* dataIn );
void printMatrix();
};
template<class T, unsigned N>
void Matrix<T, N>::fillMatrix( const T* dataIn ) {
for( unsigned int i = 0; i < Size; i++ ) {
this->data[i] = dataIn[i];
}
}
template<class T, unsigned N>
void Matrix<T, N>::printMatrix() {
for( unsigned int i = 0; i < Stride; i++ ) {
for( unsigned int j = 0; j < Stride; j++ ) {
std::cout << this->data[i*Stride + j] << " ";
}
std::cout << '\n';
}
}
int main() {
// 2x2 = 4
double ain[4] = { 1,2,3,4 };
double bin[4] = { 5,6,7,8 };
Matrix<double, 2> A;
Matrix<double, 2> B;
A.fillMatrix( ain );
A.printMatrix();
std::cout << '\n';
B.fillMatrix( bin );
B.printMatrix();
std::cout << '\n';
// test A again
A.printMatrix();
std::cout << '\n';
B.printMatrix();
std::cout << '\n';
// Try it with other types
// 3x3 = 9
char data[9] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' };
Matrix<char, 3> C;
C.fillMatrix( data );
C.printMatrix();
std::cout << '\n';
return 0;
}
Output:
1 2
3 4
5 6
7 8
1 2
3 4
5 6
7 8
a b c
d e f
g h i
With this type of design using templates you are not restricted to just using a single type such as int, float etc. You can even use User Defined Types. The only thing here that you would need to consider is any kind of operators you may have. Also the way this class is written it will always create a MxM matrix which will always be a square matrix. If you need a non square matrix; you can just add to this class by adding in a 2nd unsigned constant value to the template parameter list and renaming them accordingly for MxN. Then just substitute where they belong in the math. It would look something like this:
template<class T, unsigned M, unsigned N>
class Matrix {
private:
static const unsigned Row = M;
static const unsigned Col = N;
static const unsigned Size = Row * Col;
T data[Size] = {};
};
Now how you label them might depend on if you want Row-Col major or Col-Row major...

Initializing an std::array with an std::intializer_list passed as a parameter

I am implementing a Matrix class in C++ and I want to be able to initialize it with an intializer list like so:
Matrix<double, 2, 3> m({{1,2,1},
{0,1,1}});
In the class I have implemented the constructor like this:
template<typename Ty, unsigned int rows, unsigned int cols>
class Matrix
{
std::array<std::array<Ty, cols>, rows> data;
public:
Matrix(const std::initializer_list<std::initializer_list<Ty>>& list)
{
int i = 0;
for (auto& list_row : list)
{
int j = 0;
for (auto& list_value : list_row)
{
data[i][j++] = list_value;
}
i++;
}
}
}
The code work but I have a couple of questions. Is it possible to make it safe, so it only takes initializer lists of a certain size(the size of the matrix) and secondly can I make the code more concise - I had imagined something like this:
Matrix(const std::initializer_list<std::initializer_list<Ty>>& list)
: data(list)
{ }
And it doesn't work but any better way to do it would be appreciated.
There's a pretty easy way to make it safe:
template<typename Ty, unsigned int rows, unsigned int cols>
class Matrix
{
std::array<std::array<Ty, cols>, rows> data;
public:
Matrix(std::array<std::array<Ty, cols>, rows> const& in)
: data(in)
{ }
};
This lets you almost use the syntax you want - you just need one extra set of {}s.
There's no way to statically enforce the size of a std::initializer_list - you'd have to assert or throw to prevent me from passing in a bunch of extra values and causing you to perform out-of-range writes.

How to return two-dimensional arrays in C++

I am trying to implement a Matrix4x4 class for my port of 3D Engine that I had made earlier. Here is what I have so far in my header file:
#ifndef MAT4_H
#define MAT4_H
class Matrix4
{
public:
Matrix4() {}
float[4][4] getMatrix() { return m; }
//...
//other matrix related methods are omitted
//...
private:
float m[4][4];
};
#endif
But the method that is supposed to return the two-dimensional array causes this error:
src/Matrix4.h:13:10: error: expected unqualified-id before '[' token
float[4][4] getMatrix() { return m; }
^
I am sorry if this question already has an answer, but the answers that I found on this site were usually about returning pointers instead of an array. Hope you can help, thanks.
I would suggest to use std::array. But using it directly in code, as multi array, is a bit ugly. So I'd suggest an alias, defined as:
#include <array>
namespace details
{
template<typename T, std::size_t D, std::size_t ... Ds>
struct make_multi_array
: make_multi_array<typename make_multi_array<T,Ds...>::type, D> {};
template<typename T, std::size_t D>
struct make_multi_array<T,D> { using type = std::array<T, D>; };
}
template<typename T, std::size_t D, std::size_t ... Ds>
using multi_array = typename details::make_multi_array<T,D,Ds...>::type;
Then use it as:
public:
multi_array<float,4,4> getMatrix() { return m; }
private:
multi_array<float,4,4> m;
You could use the alias in other places as well, such as:
//same as std::array<int,10>
//similar to int x[10]
multi_array<int,10> x;
//same as std::array<std::array<int,20>,10>
//similar to int y[10][20]
multi_array<int,10,20> y;
//same as std::array<std::array<std::array<int,30>,20>,10>
//similar to int z[10][20][30]
multi_array<int,10,20,30> z;
Hope that helps.
Passing an array in either C or C++ is possible by a passing pointer to its first element- the pointer is passed by value.
The only way to pass your array by value would be to encapsulate it
in a struct, but in most cases its better to pass a pointer then to copy all the data by value.
Just return a pointer to the first element of the array! :)

Nested templates and constructor

Edit:
Note that my final purpose here is not having the class working, is just learning more about templates :-)
Suppose you have a template class which implements a vector:
template <typename T>
class Vector
{
public:
Vector(size_t dim) {
dimension = dim;
elements = new T[dim];
}
/* Here more stuff, like operator[] etc... */
private:
size_t dimension;
T * elements;
}
And suppose you want to build a matrix with it. A matrix is just a vector of vectors, thus it can be designed as follows:
template <typename T>
class Matrix : public Vector<Vector<T> >
{
/*...*/
}
And here comes trouble: In the constructor I need to provide rows and columns as parameter to the internal vectors. It should be something like
template <typename T>
Matrix<T>::Matrix (size_t ncols, size_t nrows)
: Vector<Vector<T> > /* Here I need to specify size for both
* internal and external vectors */
{
}
Obviously I cannot write Vector<Vector<T>(nrows)>(ncols), but that's what I would need!
A possible solution would be including size inside the template:
template <typename T, size_t N>
class Vector
{
public:
Vector() {
elements = new T[N];
}
/* Here more stuff, like operator[] etc... */
private:
T * elements;
}
Hence I would no longer need constructor parameters, but this also forces me to write clumsy code with templates everywhere (by exmample, every function using a Vector should be declared as
template <typename T, size_t N>
void foo (Vector<T,N> &vec) {...}
Do you have better solutions?
EDIT:
As solution I took inspiration from Mr Fooz's and chubsdad's posts. That's how I fixed the problem:
/* The RowAccess class is just an array wrapper which raises an exception
* if you go out of bounds */
template <typename T>
class RowAccess
{
public:
RowAccess (T * values, unsigned cols) : values(vals), cols(c) {}
T & operator[] (unsigned i) throw (MatrixError) {
if (i < cols) return values[i];
else throw MatrixError("Column out of bound");
}
private:
T * values;
unsigned cols;
};
template <typename T>
class Matrix
{
public:
Matrix (unsigned rows, unsigned cols) {...}
virtual ~Matrix () {...}
RowAccess<T> operator[] (unsigned row) {
if (row < rows) return RowAccess<T>(values + cols * row, cols);
else throw MatrixError("Row out of boundary");
}
private:
unsigned rows;
unsigned cols;
T * values;
};
Thanks a lot to everyone!
In OO terms, I would vote for "has" a relationship between Matrix and a Vector. A Matrix has vectors, rather than a Matrix "is a" vector, which means that Matrix should not derive from Vector.
EDIT 1: A small correction. "..which means that Matrix should not derive "publicly" from Vector". Private inheritance may be still fine.
Use placement-new like this (burried behind the uninitialized_fill call)
template <typename T>
class Vector
{
public:
Vector(size_t dim, T const& c = T()) {
dimension = dim;
elements =
static_cast<T*>(operator new(sizeof(T) * dim));
std::uninitialized_fill(elements, elements + dim, c);
}
/* Here more stuff, like operator[] etc... */
private:
size_t dimension;
T * elements;
};
Then you can call the constructor with Matrix::Vector(ncols, Vector<T>(nrows)) (you don't need to repeat the argument for the outer Vector, because Vector refers to Vector< Vector<T> > automatically since you inherit from the outer Vector. You need to make sure to call destructors manually before doing operator delete(elements) in the destructor then.
You might also want to embed the vector as a member, which i would probably prefer because I imagine not necessarily all operations of the outer vector make sense for a matrix. Then the initialization looks like m(ncols, Vector<T>(nrows)).
It should be noted that std::vector can also be used for this
template <typename T>
class Vector
{
public:
Vector(size_t dim, T const& c = T()):elements(dim, c)
{ }
private:
std::vector<T> elements;
};
This is an easy and safe way to accomplish that, and you get automatic memory management.
This isn't what you asked, but there's a good chance the matrix would be better of implemented as a single linear vector where you provide high-level access methods that do the indexing (e.g. elmLoc=row*ncols+col). This way you don't need to create and initialize a vector of vectors. You also don't need to worry about accidentally having some inner vectors of the differing size. All dense matrix implementations I have ever used use a single linear vector as the underlying implementation.
It depends on what you expect from your Vector (and Matrix) class.
Either you want the size to be determined at runtime, and in that case, I'd suggest adding a resize() function which would allow you to size the Vector in the constructor as you like.
template <typename T>
class Vector
{
public:
Vector(size_t dim) {
dimension = dim;
elements = new T[dim];
}
Vector() : dimension(0), elements(0) {} // you need default constructor
void resize(size_t dim) { // note: this could be implemented a lot better
T* new_elements=new T[dim];
for(int i=0; i<dim && i<dimension; i++)
new_elements[i]=elements[i];
delete [] elements;
elements=new_elements; dimension=dim;
}
/* Here more stuff, like operator[] etc... */
private:
size_t dimension;
T * elements;
}
You would then resize your Vectors in the Matrix constructor in a loop.
If you want the size of your vector or matrix to be determined at compile time, the best thing probably would be to use the template non-type argument as you suggested.