C++ operator+ and operator+= overloading - c++

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);
}
}
}

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

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;
}

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.

Related

How should I implement a copy constructor & assignment operator for a matrix class?

I have a matrix class with fields like this:
template <typename T>
class Matrix
{
private:
T **matrix = nullptr;
int rows;
int cols;
At this stage, I have written an assignment operator and a copy constructor. But firstly, there is code duplication, how can it be avoided, and secondly, they seem very similar to me, how can these methods be improved to look normal?
Matrix(const Matrix &matrix_) : rows(matrix_.rows), cols(matrix_.cols)
{
matrix = static_cast<T **>(new T *[rows]);
for (int i = 0; i < rows; i++)
{
matrix[i] = static_cast<T *>(new T[cols]);
}
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
matrix[i][j] = matrix_[i][j];
}
}
}
Matrix &operator=(const Matrix &matrix_)
{
if (&matrix == this)
{
return *this;
}
clean();
rows = matrix_.rows;
cols = matrix_.cols;
matrix = static_cast<T **>(new T *[rows]);
for (int i = 0; i < rows; i++)
{
matrix[i] = static_cast<T *>(new T[cols]);
}
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
matrix[i][j] = matrix_[i][j];
}
}
}
void clean()
{
if (cols > 0)
{
for (int i = 0; i < rows; i++)
{
delete[] matrix[i];
}
}
if (rows > 0)
{
delete[] matrix;
}
}
According to the condition of the assignment, it is forbidden to use STL containers, I must implement the controls myself
Added move semantics
Matrix(Matrix &&other) noexcept : rows(std::move(other.rows)), cols(std::move(other.cols)), data(new T(rows * cols))
{
other.data = nullptr;
rows = 0;
cols = 0;
}
Matrix &operator=(Matrix &&other) noexcept
{
if (&other == this)
{
return *this;
}
if (rows != other.rows && cols != other.cols)
{
std::cout << "Error assigning matrices of different sizes" << std::endl;
exit(-1);
}
clean();
std::swap(data, other.data);
std::swap(rows, other.rows);
std::swap(cols, other.cols);
return *this;
}
Generally, if you need common code between methods, the best way is to factor out the common code into (private) helper methods. For example, you might have a method alloc_ that has the loop calling new and a free_ that calls delete. Then you could have:
Matrix(const Matrix &a) : rows(a.rows), cols(a.cols) {
alloc_();
copy_(a);
}
Matrix &operator=(const Matrix &a) {
free_();
rows = a.rows;
cols = a.cols;
alloc_();
copy_(a);
}
~Matrix() { free_(); }
Use a 1D array then. It will be much cleaner and simpler and faster than an array of pointers to arrays... You can do something like:
template <typename T>
class Matrix
{
private:
// Note: Assuming T is a trivial type, most likely a fundamental type...
T* data; // Flattened matrix with size = rows*cols. Be careful,
// for really big matrices this multiplication could overflow!!!
// You can use unsigned type since negative size is a nonsense...
unsigned int rows;
unsigned int cols;
public:
Matrix(const Matrix& other)
: data(new T[other.rows*other.cols])
, rows(other.rows)
, cols(other.cols)
{
/// You can do this:
/// for(int i = 0; i < rows*cols; ++i)
/// data[i] = other.data[i];
/// or simply call the copy assign operator:
operator=(other);
}
Matrix& operator=(const Matrix& other)
{
// This is only for matrix with the same dimensions.
// Delete and allocate new array if the dimensions are different.
// This is up to the OP if he can have differently sized matrices or not...
// Also assert will "disappear" if NDEBUG (ie. in release) is defined.
assert(rows == other.rows);
assert(cols == other.cols);
for(int i = 0; i < rows*cols; ++i)
data[i] = other.data[i];
return *this;
}
};
Note: You will also need to define the constructor(s) and destructor of course...
I'm pretty sure you can't make it much simpler than this...

Is there a way to extract outer loops of multiple similar functions?

Example: I want to extract the nested for loops from these operator functions that are the same except the one line.
// Add two matrices
Matrix& operator+=(const Matrix& other)
{
for (int i = 0; i < this->m_rows; i++)
{
for (int j = 0; j < this->m_cols; j++)
{
(*this)(i, j) = (*this)(i, j) + other(i, j); // Only difference
}
}
return *this;
}
// Subtract two matrices
Matrix& operator-=(const Matrix& other)
{
for (int i = 0; i < this->m_rows; i++)
{
for (int j = 0; j < this->m_cols; j++)
{
(*this)(i, j) = (*this)(i, j) - other(i, j); // Only different
}
}
return *this;
}
You can write a function template that accepts a binary function and applies it on all pairs of elements inside the loops
template<typename Op>
void loops(const Matrix& other, Op op)
{
for (int i = 0; i < this->m_rows; i++)
{
for (int j = 0; j < this->m_cols; j++)
{
(*this)(i, j) = op((*this)(i, j), other(i, j));
}
}
}
and then use it like this
// Add two matrices
Matrix& operator+=(const Matrix& other)
{
loops(other, std::plus{});
return *this;
}
// Subtract two matrices
Matrix& operator-=(const Matrix& other)
{
loops(other, std::minus{});
return *this;
}
I'd argue that this sort of problem often implies a poor abstraction.
In the example case, an efficient matrix will have a single contiguous array, where matrix(i,j) is translated to array[i*n_columns+j] behind the scenes. The i,j interface is simpler in many cases (otherwise you'd just use a vector), but there's no reason to restrict the user accessing the underlying array elements directly - let alone within your own matrix class!
Another way to put it is that you're using classes that create the (i,j) abstraction for you, and now you're wanting another layer of abstraction to undo the work. This is costly in cpu time and in your time, and makes for spaghetti code. Instead, make sure that you (and your user) has access to the underlying array by direct element access and by iterator:
public:
auto & operator [] (size_t i)
{
return data[i]; // our underlying array
}
const auto & operator [] (size_t i) const
{
return data[i];
}
Matrix& operator += (const Matrix& other)
{
for (size_t i = 0; i < size(); ++i)
data[i] += other[i];
return *this;
}
Matrix& operator -= (const Matrix& other)
{
for (size_t i = 0; i < size(); ++i)
data[i] -= other[i];
return *this;
}
You may think that this somehow breaks encapsulation, but it doesn't. The user has the same access to edit elements, but no access to change the matrix size or access to the raw pointer. However, for the sake of answering your more general question about avoiding loops, I'll pretend we only have access to the iterators:
Matrix& operator += (const Matrix& other)
{
auto it1 = begin();
auto it2 = other.begin();
for (size_t i = 0; i < size(); ++i)
it1[i] += it2[i];
return *this;
}
Matrix& operator -= (const Matrix& other)
{
auto it1 = begin();
auto it2 = other.begin();
for (size_t i = 0; i < size(); ++i)
it1[i] -= it2[i];
return *this;
}
Okay, that's better, but we can abstract the repetitive part for any iterator or container, like so:
template <class Func, class ... Its>
void ForArrays (size_t size, Func&& f, Its && ... its)
{
for (size_t i = 0; i < size; ++i)
f(its[i]...);
}
template <class Func, class ... Cs>
void ForContainers (Func&& f, Cs && ... cs)
{
size_t size = (cs.size(), ...);
assert(((size == cs.size()) && ...));
ForArrays(size, f, cs.begin()...);
}
Demo
And now we can rewrite our operators:
Matrix& operator += (const Matrix& other)
{
ForContainers([](auto& lhs, auto rhs){lhs += rhs}, *this, other);
return *this;
}
Matrix& operator -= (const Matrix& other)
{
ForContainers([](auto& lhs, auto rhs){lhs -= rhs}, *this, other);
return *this;
}
I think the lesson here is to never undo the work of an abstraction; instead, if it's not useful for part of your code then avoid it entirely (in that part of the code). A layer of abstraction to undo a layer of abstraction is why some people turn away from OOP.

How to overload + to sum 2 objects that are matrix in c++?

i have this class
class Matrix
{
int size;
std::unique_ptr<std::unique_ptr<int[]>[]> val;
public:
Matrix(int size1)
{
size=size1;
val=std::make_unique< std::unique_ptr<int[]>[] >(size);
...
}
... move constructor,move assignment operator
Matrix& operator+(Matrix &m)
{
Matrix sumMatrix(size);
for ( int i = 0; i < size; ++i)
{
for (int j = 0; j < size; ++j){
sumMatrix.val[i][j]=this->val[i][j]+m.val[i][j];
}
}
return sumMatrix;
}
and main :
...
Matrix e=b+c;
std::cout<<"e="<<std::endl;
e.print();
and i have this error :
warning: reference to local variable 'sumMatrix' returned
[-Wreturn-local-addr]
Matrix sumMatrix(size);
Can someone please help me with this ??
Return by value, as you should for operator+ most of the time:
// vvv--Removed & vvvvv-----vvvvv--Const is more appropriate here
Matrix operator+(Matrix const &m) const { ... }
This will require a copy constructor, make sure to add that. Also note that you should probably collect your for-loop logic into an operator+= and simplify operator+ significantly while providing more functionality for the end-user:
Matrix& operator+=(Matrix const& m) {
for (int i = 0; i < size; ++i) {
for (int j = 0; j < size; ++j) {
//vvv--No need for this-> in C++
val[i][j] += m.val[i][j];
}
}
return *this;
}
Matrix operator+(Matrix const& m) const {
Matrix sumMatrix{m}; // requires a copy constructor.
sumMatrix += *this;
return sumMatrix;
}

C++ Matrix Operator+

The method template <class T> const Matrix<T> Matrix<T>::operator+(const Matrix<T> &rhs) const for program matrix.cc should be able to return the sum of calling object's matrix and rhs's matrix as a new object. Also, the lhs and rhs rows and cols will be equal.
The error output that I am receiving from the compiler is:
[hw7] make clean && make bin/test_add && ./bin/test_add UserSettings ✱
rm -f bin/*
g++ -std=c++11 -Wall -I inc -I src -c src/test_matrix_add.cc -o bin/test_matrix_add.o
g++ -std=c++11 -Wall -I inc -I src -o bin/test_add bin/test_matrix_add.o
Testing Matrix::operator+
Expected Matrix2[0][0]: 3.0, Actual: 1
FAILED
Could someone let me know why I receive this "Failed" output when I know I pass the // TEST MUL ASSIGMENT OP CORRECT RETURN section.
Here is my matrix.cc:
#include <matrix.h>
template <class T>
Matrix<T>::Matrix() {
rows_ = 0;
cols_ = 0;
m_ = nullptr;
}
template <class T>
Matrix<T>::Matrix(unsigned int rows, unsigned int cols)
: rows_(rows), cols_(cols) {
m_ = new T *[rows_];
for (unsigned int i = 0; i < rows_; ++i) {
m_[i] = new T[cols_];
}
}
template <class T>
Matrix<T>::Matrix(const Matrix<T> &that) {
rows_ = that.rows_;
cols_ = that.cols_;
m_ = new T *[rows_];
for (unsigned int i = 0; i < rows_; ++i) {
m_[i] = new T[cols_];
for (unsigned int j = 0; j < cols_; ++j) {
m_[i][j] = that.m_[i][j];
}
}
}
template <class T>
Matrix<T>::~Matrix() {
for (unsigned int i = 0; i < rows_; ++i) {
delete[] m_[i]; // delete columns
}
delete[] m_; // delete columns
}
template <class T>
T Matrix<T>::Get(unsigned int row, unsigned int col) const {
if (row > rows_ && col > cols_) {
throw std::out_of_range("error: index out of range");
}
return this->m_[row][col];
}
template <class T>
const Matrix<T> &Matrix<T>::operator=(const Matrix<T> &rhs) {
if (this == &rhs) {
return *this;
} // returns the address
for (unsigned int i = 0; i < rows_; ++i) {
delete[] m_[i];
}
delete[] m_;
rows_ = rhs.rows_;
cols_ = rhs.cols_;
m_ = new T *[rows_];
for (unsigned int i = 0; i < rows_; ++i) {
m_[i] = new T[cols_];
for (unsigned int j = 0; j < cols_; ++j) {
m_[i][j] = rhs.m_[i][j];
}
}
return *this;
}
template <class T>
const Matrix<T> &Matrix<T>::operator*=(T rhs) {
for (unsigned int i = 0; i < rows_; ++i) {
for (unsigned int j = 0; j < cols_; ++j) {
m_[i][j] *= rhs;
}
}
return *this;
}
template <class T>
const Matrix<T> Matrix<T>::operator+(const Matrix<T> &rhs) const {
if (!(this->cols_ == rhs.cols_) || (this->rows_ == rhs.rows_)) {
std::cout << "Cannont add matrices. Wrong dimensions\n";
exit(0);
}
Matrix<T> lhs;
lhs.rows_ = this->rows_;
lhs.cols_ = this->cols_;
for (unsigned int i = 0; i < lhs.rows_; ++i) {
for (unsigned int j = 0; j < lhs.cols_; ++j) {
lhs[i][j] += rhs[i][j];
}
}
return lhs;
}
Here is my matrix.h:
#include <cassert>
// using assert
#include <exception>
#include <iostream>
template <class T>
class Matrix {
public:
friend class MatrixTester;
Matrix(); // for testing, useless in practice
Matrix(unsigned int rows, unsigned int cols);
Matrix(const Matrix<T> &that);
~Matrix();
T Get(unsigned int row, unsigned int col) const;
const Matrix<T> &operator=(const Matrix<T> &rhs);
const Matrix<T> &operator*=(T rhs);
const Matrix<T> operator+(const Matrix<T> &rhs) const;
private:
T **m_;
unsigned int rows_;
unsigned int cols_;
};
#include <matrix.cc> //NOLINT
This is my test_matrix_add.cc tester:
#include <test_matrix.h>
int main(int argc, char** argv) {
MatrixTester tester;
cout << "Testing Matrix::operator+" << endl;
if (tester.Test_AddOp()) {
cout << " PASSED" << endl;
return 0;
}
cout << " FAILED" << endl;
return 1;
}
bool MatrixTester::Test_AddOp() const {
const int kRows = 4, kCols = 5;
Matrix<double> m1;
m1.m_ = new double*[kRows];
for (unsigned int i = 0; i < kRows; ++i) {
m1.m_[i] = new double[kCols];
for (unsigned int j = 0; j < kCols; ++j)
m1.m_[i][j] = (i + 1.0) * (j + 1.0);
}
m1.rows_ = kRows;
m1.cols_ = kCols;
// TEST ADDITION CORRECTNESS
Matrix<double> m2;
m2 = m1;
// + m1 + m1;
if (m2.m_[0][0] != 3) {
cout << " Expected Matrix2[0][0]: 3.0, Actual: " << m2.m_[0][0] << endl;
return false;
}
if (m2.m_[1][3] != 24.0) {
cout << " Expected Matrix2[1][3]: 24.0, Actual: " << m2.m_[1][3] << endl;
return false;
}
if (m2.m_[2][2] != 27.0) {
cout << " Expected Matrix2[2][2]: 27.0, Actual: " << m2.m_[2][2] << endl;
return false;
}
if (m2.m_[3][4] != 60.0) {
cout << " Expected Matrix2[2][2]: 60.0, Actual: " << m2.m_[2][2] << endl;
return false;
}
return true;
}
Firstly, there is way too much code here.
To address your problem, I see don't see you allocating memory to lhs.m_. This is a problem because you initialize lhs with the default constructor, which only assigns this->m_ to a nullptr.
To fix this, this should work (although untested):
template <class T>
const Matrix<T> Matrix<T>::operator+(const Matrix<T>& rhs) const
{
if (!(this->cols_ == rhs.cols_) || (this->rows_ == rhs.rows_))
{
std::cout << "Cannot add matrices. Wrong dimensions\n";
exit(0);
}
Matrix<T> lhs;
lhs.rows_ = this->rows_;
lhs.cols_ = this->cols_;
// Allocate memory for `lhs.m_`, like you did in your 2nd constructor
lhs.m_ = new T* [rows_];
for (unsigned i = 0; i < rows_; ++i)
{
m_[i] = new T[cols_];
}
// [End] allocation
for (unsigned int i = 0; i < lhs.rows_; ++i)
{
for (unsigned int j = 0; j < lhs.cols_; ++j)
{
lhs[i][j] += rhs[i][j];
}
}
return lhs;
}
Also, somewhat unrelated, be careful that you consistently treat m_ as a double-pointer. I didn't read all your code, but just be cautious. And also remember that you have to deallocate all the memory you allocated with new in your destructor. Personally, I believe you should use smart pointers from <memory> (e.g. std::unique_ptr, etc), which you can learn more about here. Using smart pointers would make the pointers deallocate the memory on their own and you wouldn't have to worry about memory leaks.
Edit 1
As walnut stated, a better solution would be to just call the 2nd constructor, which will allocate the memory for you. So, your revised function would be:
template <class T>
/**
Note:
> When you call this function (e.g. Matrix<T> new_mat = mat1 + mat2),
`mat1` is `this` and `mat2` is what you're calling `rhs`. I've done
some renaming and corrected your logic errors here
*/
const Matrix<T> Matrix<T>::operator+(const Matrix<T>& other) const
{
if (!(this->cols_ == other.cols_) || (this->rows_ == other.rows_))
{
std::cout << "Cannot add matrices. Wrong dimensions\n";
exit(0);
}
// Call the 2nd constructor
Matrix<T> res(this->rows_, this->cols_);
for (unsigned i = 0; i < res.rows_; ++i)
{
for (unsigned j = 0; j < res.cols_; ++j)
{
res.m_[i][j] = this->m_[i][j] + other.m_[i][j];
}
}
return res;
}
Edit 2
The above code has been correct to add the matrices correctly, as per #walnut's comment.

Checking the matrix size

I don't really know how to check the size of both matrices, if they are appropriate to be added.
Here's my code, which is currently running without errors:
matrix operator+(const matrix & mat){
matrix add;
add.mSize = mat.mSize;
add.mP = new int[add.mSize * add.mSize];
for(int i = 0; i < add.mSize * add.mSize; i++){
add.mP[i] = mP[i] + mat.mP[i];
}
return add;
}
A general 2d matrix has two different dimensions, rows and columns (unless it is the particular case of a square matrix).
In the general case, your code could be:
#include <stdexcept>
class matrix
{
public:
matrix(int rows, int columns) :
mRows(rows), mColumns(columns), mP(NULL)
{
mP = new double[mRows * mColumns];
for (int i = 0; i < mRows * mColumns; i++)
mP[i] = 0.0;
}
matrix(const matrix& other) :
mRows(other.mRows), mColumns(other.mColumns), mP(NULL)
{
mP = new double[mRows * mColumns];
for (int i = 0; i < mRows * mColumns; i++)
mP[i] = other.mP[i];
}
~matrix()
{
delete[] mP;
}
const double* operator[] (int row) const {
return &mP[row * mColumns];
}
double* operator[] (int row) {
return &mP[row * mColumns];
}
matrix& operator=(const matrix& other) {
if (this == &other) return *this;
if ((mRows != other.mRows) || (mColumns != other.mColumns)) throw std::invalid_argument( "dimensions don't match" );
for (int r = 0; r < mRows; r++) {
for (int c = 0; c < mColumns; c++) {
(*this)[r][c] = other[r][c];
}
}
return *this;
}
matrix& operator+=(const matrix& other) {
if ((mRows != other.mRows) || (mColumns != other.mColumns)) throw std::invalid_argument( "dimensions don't match" );
for (int r = 0; r < mRows; r++) {
for (int c = 0; c < mColumns; c++) {
(*this)[r][c] += other[r][c];
}
}
return *this;
}
private:
int mRows;
int mColumns;
double *mP;
};
inline matrix operator+(matrix lhs, const matrix& rhs)
{
lhs += rhs;
return lhs;
}