C++ Matrix Class - Suggestions

2020-04-15 15:08发布

I am trying to build a templated Matrix class in C++. Below is its implementation. I implemented two operators +,+= as of now just to give an idea on how it will look and I thought it would be best to ask for feedback before I proceed any further.

The whole implementation is public and also there are no explicit bound/error checks, this is because its not meant to be a full fledged matrix library and hence avoided unnecessary code.

It would be very helpful if someone could comment on it and may be suggest a few improvements or suggestions.

Thank you.

template<class T>
class Matrix
{
    public:
    int r,c;
    vector< vector< T > >mat;

    Matrix() {}

    // Constructor to set the size of the matrix
    Matrix(int _r,int _c)
    {
        r=_r;c=_c;
        mat.resize(r);
        for(int i=0;i<r;i++)
            mat[i].resize(c);
    }
    // Constructor to build a matrix from a C 2d array
    // Pointer to the first element is passed (&arr[0][0])
    Matrix(T *arr,int _r,int _c)
    {
        r=_r;c=_c;
        mat.resize(r);
        for(int i=0;i<r;i++)
            for(int j=0;j<c;j++)
                mat[i].push_back(arr[i*c+j]);
    }
    template<typename U>
    Matrix<T>& operator +=(const Matrix<U>&M)
    {
        for(int i=0;i<r;i++)
            for(int j=0;j<c;j++)
                mat[i][j]+=static_cast<T>(M.mat[i][j]);
        return *this;
    }
    template<typename U>
    Matrix<T> operator +(const Matrix<U>&M)
    {
        Matrix<T>tmp=*this;
        return tmp+=M;
    }
};

template<typename T>
istream& operator >>(istream &in,Matrix<T>&M)
{
    in>>M.r>>M.c;
    Matrix<T>tmp(M.r,M.c);
    for(int i=0;i<M.r;i++)
        for(int j=0;j<M.c;j++)
            in>>tmp.mat[i][j];
    M=tmp;
    return in;
}
template<typename T>
ostream& operator <<(ostream &out,Matrix<T>M)
{
    for(int i=0;i<M.r;i++)
    {
        for(int j=0;j<M.c;j++)
            cout<<M.mat[i][j]<<" ";
        cout<<endl;
    }
    return out;
}

EDIT: Thank you all for the suggestions.

I just have one small question, say I do want to implement error checking (ex: checking for bounds,valid arguments etc..) however I do want the provide user with an option to disable error checking completely, is there any good way to implement this ? What I need is something like example:`ios_base::sync_with_stdio(0);. Thanks again.

9条回答
爷、活的狠高调
2楼-- · 2020-04-15 15:15

You're wasting your time keeping _r and _c because the vectors keep their own sizes.

查看更多
Animai°情兽
3楼-- · 2020-04-15 15:23

If you want to know how it's done properly, see the Eigen project's implementation:

https://bitbucket.org/eigen/eigen/src/49e00a2e570c/Eigen/src/Core/Matrix.h

https://bitbucket.org/eigen/eigen/src/49e00a2e570c/Eigen/src/Core/MatrixBase.h

Eigen is a template-heavy fast matrix library for C++. I'm sure there's a lot of usefulness there.

查看更多
兄弟一词,经得起流年.
4楼-- · 2020-04-15 15:28

1 .Use initializer lists for constructor like, Matrix (...) : r(_r), c(_c)

2.operator + can be simply { return this->Add(M) } (assuming that typenames T and U are compatible and you have implemented some Add() method). 3. If you are constructing something from 2D array then use below technique:

template<typename T>
class Matrix {
public: // ...
  void Construct (T *arr)
  {
    mat.resize(r);
    for(int i=0;i<r;i++)
      for(int j=0;j<c;j++)
        mat[i].push_back(arr[i*c+j]);
  }
  template<size_t ROW, size_t COL>
  Matrix(T (&arr)[ROW][COL]) : r(ROW), c(COL)
  {
    Construct(arr);
  }
//...
};

Thus you don't have to pass the size of the 2D array when you are calling and it will reduce the probability of errors.

  1. For better readability, you can use better names for class members: either this->r or t_r.
查看更多
▲ chillily
5楼-- · 2020-04-15 15:28

I wonder why you used the very expensive push_back function in this Class initialization:

// Pointer to the first element is passed (&arr[0][0])
Matrix(T *arr,int _r,int _c)
{
    r=_r;c=_c;
    mat.resize(r);
    for(int i=0;i<r;i++)
        for(int j=0;j<c;j++)
            mat[i].push_back(arr[i*c+j]);
}

Since you already have the number of rows and columns, consider this:

// Pointer to the first element is passed (&arr[0][0])
Matrix(T *arr,int _r,int _c)
{
    r=_r;c=_c;
    mat.resize(r);
    for(int i=0;i<r;i++)
        mat[i].resize(c);
        for(int j=0;j<c;j++)
            mat[i][j]= arr[i*c+j];
}
查看更多
做个烂人
6楼-- · 2020-04-15 15:32

If speed is what you have in mind, don't implement a matrix library yourself but use Boost libraries, I've used them in some projects and do pretty well on both 32 and 64 bit architectures

查看更多
▲ chillily
7楼-- · 2020-04-15 15:35

I wouldn't use a vector of vectors to achieve this. This way you're adding quite some overhead to all lookups without any real need for it. Just allocate a one or two dimensional array of T and use that one within your class instead. This would also allow fast copying to other object instances without having to iterate through all fields as well as resetting the whole matrix.

Also you should make your members const when they shouldn't be changed later on (in your example r and c). To initialize them just use the constructor list in Tony's post.

查看更多
登录 后发表回答