How to overload + to sum 2 objects that are matrix in c++? - 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;
}

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...

How can I sum two complex matrix in C++? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I have a class for complex numbers whose data members are im (the imaginary part) and re (the real part). Now I want to sum 2 matrix that come from the class Matrix (A and B) and put the sum in another matrix (C). This is what I tried. Any advice?
The error I get is
no match for 'operator[]' (operand types are 'Matrix' and 'int')
inline Matrix& operator+(Matrix& A, Matrix& B)
{
Matrix *C = new Matrix;
C->rows = A.rows;
C->columns = A.columns;
for(int i = 0; i < A.rows; i++)
for(int j = 0; j < A.columns; j++)
C[i][j] = A[i][j] + B[i][j];
}
return **C;
}
Add a operator '+' inside class like:
Matrix Matrix::operator+(const Matrix &other){
Matrix result = Matrix<T>(rows, other.columns);
if (this->rows == other.columns && this->columns == other.rows) {
for (int i = 0; i < this->rows; i++) {
for (int j = 0; j < this->columns; j++) {
result.n[i][j] = other.n[i][j] + this->n[i][j];
}
}
}
return result;
}
And the operator '=' to copy the result
Matrix& Matrix::operator=(const Matrix &other ){
if(this->columns<=other.columns && this->rows<=other.rows){
for(int i=0;i<this->rows;i++){
for(int j=0;j<this->columns;j++){
this->n[i][j]=other.n[i][j];
}
}
return (*this);
}else{
printf("ERROR");
}
}
Here's a basic Matrix implementation you could use.
Compatible with std::complex or whatever you own type is, as long as it's copy-constructible (see the main() in the link below).
template<class T>
struct Matrix {
std::vector<T> data;
size_t rows, cols;
Matrix(size_t rows_, size_t cols_, T value=T())
: data(rows_*cols_, value)
, rows(rows_)
, cols(cols_)
{
}
Matrix() = default;
Matrix(const Matrix& other) = default;
Matrix& operator=(const Matrix& other) = default;
Matrix(Matrix&& other) = default;
Matrix& operator=(Matrix&& other) = default;
T& operator()(size_t row, size_t col) {
return data.at(flatIndex(row, col));
}
const T& operator()(size_t row, size_t col) const {
return data.at(flatIndex(row, col));
}
Matrix operator+(const Matrix& other) const {
assert(data.size() == other.data.size());
assert(rows == other.rows);
assert(cols == other.cols);
Matrix sum = *this;
for (size_t i=0; i<data.size(); i++) {
sum.data.at(i) += other.data.at(i);
}
return sum;
}
protected:
size_t flatIndex(size_t row, size_t col) const {
return row * cols + col;
}
};
template<class T>
std::ostream& operator<<(std::ostream& os, const Matrix<T>& m) {
for (size_t r = 0; r<m.rows; r++) {
for (size_t c = 0; c<m.cols; c++) {
os << m(r, c) << " ";
}
os << '\n';
}
return os;
}
https://godbolt.org/z/Gvx5ac
If you really need performant/safe matrices, consider using a LinAlg library instead, like Eigen.

Overloading operator: Matrix Addition

enter image description here
I'm trying to set up my functions and perform some overloading operations so that I can +,-,==,* two matrices. I have encountered a problem at the first operation overload: addition.
My program works until i try to add 2 matrices.
Thanks for help.
include<iostream>
using namespace std;
class matrixType
{
private:
int rows,cols;
int** matrix;
public:
matrixType( int r, int c)
{
rows=r;
cols=c;
matrix = new int*[rows];
for(int i = 0; i < rows; ++i)
matrix[i] = new int[cols];
}
~matrixType()
{
for(int i = 0; i < rows; ++i)
{
delete [] matrix[i];
}
delete [] matrix;
}
matrixType operator+( matrixType m2 )
{
if( rows==m2.rows && cols==m2.cols)
{
matrixType m3(rows, cols);
for( int i=0; i<rows; i++)
{
for( int j=0; j<cols; j++)
{
m3.matrix[i][j]=matrix[i][j]+m2.matrix[i][j];
}
}
return m3;
}
}
matrixType operator-(matrixType m2)
{
if( rows==m2.rows && cols==m2.cols)
{
matrixType m3(rows, cols);
for( int i=0; i<rows; i++)
{
for( int j=0; j<cols; j++)
{
m3.matrix[i][j]=matrix[i][j]-m2.matrix[i][j];
}
}
return m3;
}
}
friend istream& operator>> (istream& stream, matrixType m)
{
for ( int i=0; i<m.rows;i++)
{
for( int j=0; j<m.cols;j++)
{
cout<<"Matrix"<<"["<<i<<"]"<<"["<<j<<"]"<<"=";
stream>>m.matrix[i][j];
cout<<endl;
}
}
return stream;
}
friend ostream& operator<<(ostream& out, matrixType m)
{
for ( int i=0; i<m.rows;i++)
{
for( int j=0; j<m.cols;j++)
{
cout<<"Matrix"<<"["<<i<<"]"<<"["<<j<<"]"<<"=";
out<<m.matrix[i][j];
cout<<endl;
}
}
return out;
}
};
Totally different approach as alternative - based on templates:
template <size_t Rows, size_t Columns>
class Matrix
{
int matrix[Rows][Columns];
public:
void operator+=(Matrix<Rows, Columns> const& other)
{
for(size_t i = 0; i < Rows; ++i)
{
for(size_t j = 0; j < Columns; ++j)
{
matrix[i][j] += other.matrix[i][j];
}
}
}
Matrix<Rows, Columns>
operator+(Matrix<Rows, Columns> const& other) const
{
Matrix<Rows, Columns> result(*this);
result += other;
return result;
}
template<size_t C>
Matrix<Rows, C> operator*(Matrix<Columns, C> const& other) const
{
// just exemplary, actual implementation missing:
return Matrix<Rows, C>();
}
// rest of operators coming here
};
It might or might not fit your needs, but if it does, you get the rule of three for free. Additionally you are prevented automatically from adding or multiplying matrices of non-fitting sizes.
On the other hand -- well, benefits always come with some cost, too... -- you lose flexibility. Imagine you want to place arbitrary matrices into a vector - you'd need a base class then and would have to use (smart?) pointers, adding or multiplying arbitrary matrices requires casts, ...
Biggest drawback, though, is that you need to know your matrix sizes at compile time - if you don't, we are out.
By the way, adding/multiplying - in your original implementation, you do not return anything if matrix sizes do not match! You should return some kind of sentinel then, e. g. a 0x0 matrix - or possibly even better: throw some appropriate exception.
This sound like a case of rule of three violation.
You need to implement a copy constructor:
matrixType(const matrixType&)
And a copy assignment operator:
matrixType operator=(const matrixType&)
And for C++11 it might be a good idea to also implement the move constructor and move assignment operator.
matrixType(matrixType&&)
matrixType& operator=(matrixType&& other)

constructor\destructor or understanding of OOP

Im trying to to use operator overloading with both + and = operator on a matrix class which i created. either the constructor or destructor is causing a problem or it isn't either (though i grayed out each of them and both and the code seems to work). could someone please help me understand what is causing this strange behavior. when i try to create 3 matrixes a b and c then try a = b+c; it just fails.
header file
#ifndef MATRIX_H;
#define MATRIX_H;
using namespace std;
enter code here
class matrix
{
friend ostream& operator<< (ostream&, matrix &);
public:
matrix();
matrix(int,int); //constructor
matrix(const matrix&);//copy constructor
~matrix();
int getRow();
int getCol();
void setRow(int);
void setCol(int);
class arr1D{ //proxy class to allow the use of [][] operator
public:
arr1D(int* a):temp(a){}
int &operator[](int a){
return temp[a];
}
int *temp;
};
arr1D operator[](int a){
return arr1D(arr2[a]);
}
matrix& operator=(const matrix& );
matrix& operator+(const matrix& );
protected:
private:
int row , col;
int **arr2;
};
#endif // MATRIX_H
enter code here
cpp file
#include <iostream>
#include "matrix.h"
using namespace std;
matrix::matrix()
{
setCol(0);
setRow(0);
**arr2=0;
}
matrix::matrix(int x, int y) //matrix constructor creates x*y matrix and initializes to 0's
{
setCol(y);
setRow(x);
arr2 = new int * [getRow()];
if (arr2) {
for (int i = 0; i < getRow(); i++) {
arr2[i] = new int [getCol()];
};
};
for (int i=0; i<getRow();i++){
for (int j=0;j<getCol();j++){
arr2[i][j]=0;
};
};
}
matrix::matrix(const matrix &m){ //defines the copying constructor
row=m.row;
col=m.col;
arr2 = new int*[row];
for (int i=0; i<row; i++){
arr2[i] = new int[col];
}
for (int i=0; i<row; i++){
for (int j=0; j<col; j++){
arr2[i][j] = m.arr2[i][j];
}
}
}
matrix::~matrix(){ //defines the destructor
for (int i=0; i<row; i++){
delete[] arr2[i];
}
delete[] arr2;
}
int matrix::getRow(){ //getter for row
return row;
}
int matrix::getCol(){ // getter for col
return col;
}
void matrix::setRow(int x){ //setter for row
row=x;
}
void matrix::setCol(int x){ //setter for col
col=x;
}
ostream& operator<< (ostream& output, matrix& a){
int i,j;
for (i=0; i < a.getRow() ; i++){
for (j=0; j< a.getCol() ; j++){
output << " " <<a.arr2[i][j];
};
output << "\n";
};
return output;
}
matrix& matrix::operator=(const matrix& right)
{
if (this == &right) { // Same object?
return *this;
}
row = right.row;
col = right.col;
for (int i=0; i<row; i++)
{
for (int j=0; j<col; j++){
arr2[i][j]=right.arr2[i][j];
}
}
return *this ;
}
matrix& matrix::operator+(const matrix& right)
{
int row=right.row;
int col=right.col;
matrix result(row,col);
for (int i = 0; i < row; i++){
for (int j = 0; j < col; j++){
//cout<<"arr2[i][j]="<<arr2[i][j]<<endl;
//cout<<"right.arr2[i][j]="<<right.arr2[i][j]<<endl;
result.arr2[i][j]=(arr2[i][j] + right.arr2[i][j]);
//cout<<"result.arr2[i][j]="<<result.arr2[i][j]<<endl;
};
};
return result;
}
First, as the other answer pointed out, you are returning a reference to a temporary in your operator +. That is undefined behavior.
But instead of writing operator + in this fashion, what you should do is write operator += instead, and then in turn, write operator + in terms of operator +=. Since a programmer would expect += to also work for the matrix in addition to +, it makes no sense to leave out +=.
For operator +=, you would in this case return a reference to the current object.
So all we need to do is move the code in operator + to operator +=:
#include <exception>
//...
matrix& matrix::operator+=(const matrix& right)
{
if(row != right.row || col != right.col)
throw std::logic_error("Matrix not the same size");
for (int i = 0; i < right.row; i++)
{
for (int j = 0; j < right.col; j++)
arr2[i][j] += right.arr2[i][j]);
}
return *this;
}
Note that we return a reference to the current matrix, since += modifies the current matrix. Also note that we throw an exception on an illegal matrix being sent to +=. This IMO makes more sense than returning a legitimate matrix back on error. If the matrix is not the same size, the code should not try and return a matrix back.
Now operator + can be written in terms of +=:
matrix matrix::operator+(const matrix& right)
{
return matrix(*this) += right;
}
Believe it or not, that's it. All we did was create a temporary matrix and call += with the passed in argument. We return the result of this as a brand new matrix, just as we expect.
The other issue is the assignment operator. Given that you've written a copy constructor and destructor, and the copy constructor works without having to use the assignment operator, then the copy / swap idiom can be used to implement the assignment operator.
#include <algorithm>
//...
matrix& matrix::operator=(const matrix& right)
{
matrix temp(right);
std::swap(temp.arr2, arr2);
std::swap(temp.row, row);
std::swap(temp.col. col);
return *this;
}
All we did here was create a temporary matrix of the passed in object and swap out its contents with the current object's contents. When the temporary dies off at the return, the temporary destroys the old contents that were swapped out.
This method has the advantage of not only being very simple to implement (just a bunch of calls to std::swap), it is also exception safe. If there is an issue creating the temporary matrix, a std::bad_alloc exception would have been thrown, without messing up or altering any members of this. The issue with the other answer given, where you're deallocating the memory first before allocating the new memory, is solved by using the above technique.

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