jakeva
jakeva

Reputation: 2835

C++ operator+ and operator+= overloading

I'm implementing my own matrix class in c++ to help me develop my understanding of the language. I read somewhere that if you've got a working += operator, to use it in your + operator. So that's what I've got:

template <class T>
const Matrix<T>& Matrix<T>::operator+(const Matrix<T> &R){

    Matrix<T> copy(*this);
    return copy += R;
}

And here is the += operator overload:

template <class T>
const Matrix<T>& Matrix<T>::operator+=(const Matrix<T> & second_matrix){
    //Learn how to throw errors....
    if (rows != second_matrix.getNumRows() || cols != second_matrix.getNumCols()){throw "Dimension mismatch.";}
    int i,j;
    for (i = 0; i < rows; i++){
        for (j = 0; j < cols; j++){
            data[i][j] += second_matrix.get(i,j);
        }
    }
    return *this;
}

I can use the += just fine (eg, a += b; returns no errors). But calling the + operator (eg, a = b + c;) returns :

test.cpp.out(77055) malloc: *** error for object 0x300000004: pointer being freed was not allocated

Just for completeness, here's my destructor:

template <class T>
Matrix<T>::~Matrix(){
    for (int i = 1; i < rows; i++){
        delete[] data[i]; }
    delete[] data;
}

I've been using C++ for a couple years on and off, and still have trouble sometimes keeping track of pointers. I hope that's normal... Any help would be great. Thanks!

EDIT: here's my copy constructor. It was set to free the data arrays but i removed that. now I get segmentation faults.

template <class T>
Matrix<T>::Matrix(const Matrix<T>& second_matrix){

    rows = second_matrix.getNumRows();
    cols = second_matrix.getNumCols();
    data = new T*[rows];

    int i,j;
    for (i = 0; i < rows; i++){
        data[i] = new T[cols];
    }
    for (i = 0; i < rows; i++){
        for (j = 0; j < cols; j++){
            data[i][j] = second_matrix.get(i,j);
        }
    }

}

Upvotes: 10

Views: 77490

Answers (3)

Marcus Borkenhagen
Marcus Borkenhagen

Reputation: 6656

operator+() should not return a reference type as it is a new (locally declared) instance that holds the result of the operation.

Upvotes: 25

ArBR
ArBR

Reputation: 4082

This is how I have implemented such operators for a Matrix class, this is based on a Vector Class. Once you define some operators all other should be defined in terms of the simplest operators:

Matrix::Matrix(const Matrix& rMatrix) :
    _iRows(rMatrix._iRows), _iColumns(rMatrix._iColumns), _pVector(0)
{
    _pVector = new Vector[_iRows];
    for (int i = 0; i < _iRows; i++) { _pVector[i] = rMatrix._pVector[i]; }
}

Matrix& Matrix::operator=(const Matrix& rMatrix)
{
    if (this != &rMatrix)
    {
        if (0 != _pVector) { delete[] _pVector; pVector = 0; }
        _iRows = rMatrix._iRows;
        _iColumns = rMatrix._iColumns;
        _pVector = new Vector[_iRows];
        for (int i = 0; i < _iRows; i++) { _pVector[i] = rMatrix._pVector[i]; }
    }
    return *this;
}
Matrix& Matrix::operator+=(const Matrix& rMatrix)
{
    *this = *this + rMatrix;
    return *this;
}

Matrix Matrix::operator+(const Matrix& rMatrix) const
{
    Matrix matrix(_iRows, _iColumns);
    ValidateSizes(rMatrix);
    for (int i = 0; i < _iRows; i++) { matrix._pVector[i] = _pVector[i] + rMatrix._pVector[i]; }
    return matrix;
}

Matrix operator+(const Matrix& rMatrix, double dNum)
{
    Matrix matrix(rMatrix._iRows, rMatrix._iColumns);
    matrix.ValidateSizes(rMatrix);
    for (int i = 0; i < matrix._iRows; i++) { matrix._pVector[i] = dNum + rMatrix._pVector[i]; }
    return matrix;
}

Matrix operator+(double dNum, const Matrix& rMatrix)
{
    return operator+(rMatrix, dNum);
}

bool Matrix::ValidateSizes(const Matrix& rMatrix) const
{
    if (_iRows != rMatrix._iRows) { /* THROW EXCEPTION */ }
    if (_iColumns != rMatrix._iColumns) { /* THROW EXCEPTION */ }
    return true;
}

Upvotes: 4

AlexF
AlexF

Reputation: 21

If this a matrix for 3D rendering/simulation I would recommend NOT dynamically allocating the memory like that. You can end up with the memory being spread all over the place which causes caching issues. It also leads to potential memory bugs.

template <typename T>
class Matrix
{
   public:
      T   m_Data[4][4];
};

or if you want something non-4x4

template <typename T, unsigned int rows, unsigned int columns>
class Matrix
{
   public:
      T   m_Data[rows][columns];
};

and then dynamically allocate the Matrix objects.

Upvotes: 2

Related Questions