I'm trying to do some operations in two dimensional matrices. I overloaded (+ , - and *) to do the calculations. I have a problem regarding (I believe) memory management. Look at the following code:
Mtx M1(rows1,cols1,1.0); //call the constructor
Mtx M2(rows2,cols2,2.0); //call the constructor
Mtx M3(rows3,cols3,0.0); //call the constructor
M3 = M1 + M2;
cout << M3 << endl;
Mtx Mtx::operator+(const Mtx &rhs)
{
double **ETS;
ETS = new double*[nrows];
for (int i = 0; i < rhs.nrows; i++) {
ETS[i] = new double[rhs.ncols];
}
if (ETS == NULL) {
cout << "Error Allocation on the Heap" << endl;
exit(1);
}
for (int i = 0; i < rhs.nrows; i++) {
for (int j = 0; j < rhs.ncols; j++) {
ETS[i][j] = 0.0;
}
}
for (int i = 0; i < rhs.nrows; i++) {
for (int j = 0; j < rhs.ncols; j++) {
ETS[i][j] = ets[i][j];
}
}
for (int i = 0; i < rhs.nrows; i++) {
for (int j = 0; j < rhs.ncols; j++) {
ETS[i][j] = ETS[i][j] + rhs.ets[i][j];
}
}
Mtx S(nrows, ncols, ETS);
delete [] ETS;
return S;
}
I think my problem is here:
Mtx S(nrows, ncols, ETS);
delete [] ETS;
return S;
Is this a proper way to return ETS? Or do you think the problem is with the constructor? I got no output when I did the above return!
This is the constructor for Mtx S(nrows, ncols, ETS);
Mtx::Mtx(int rows, int cols, double **ETS)
{
ets = new double*[nrows];
for (int i = 0; i < nrows; i++) {
ets[i] = new double[ncols];
}
for (int i = 0; i < nrows; i++) {
for (int j = 0; j < ncols; j++) {
ets[i][j] = ETS[i][j];
}
}
}
My copy constructor:
Mtx::Mtx(const Mtx& rhs)
:nrows(rhs.nrows), ncols(rhs.ncols)
{
ets = new double*[nrows];
for (int i = 0; i < nrows; i++) {
ets[i] = new double[ncols];
}
for (int i = 0; i < rhs.nrows; i++) {
for (int j = 0; j < rhs.ncols; j++) {
ets[i][j] = rhs.ets[i][j];
}
}
}
I overloaded << to print M3. It works fine because I tested printing M1 and M2.
I also did the following, and still not working:
Mtx S(nrows, ncols, ETS);
for (int i = 0; i < rhs.nrows; i++) {
delete [] ETS[i];
}
delete [] ETS;
return S;
}
You could instead use
std::vector< std::vector<double> >
instead of
double **
that will be more safe as far as bounds are concerned. And you only have to use functions
std::vector::size()
and
std::vector::clear()
in the destructor. :)
Yes, there is a problem where you pointed out. You have to delete all the memory that is pointed to in the pointers in ETS. So, it should be more like:
for (int i = 0; i < rhs.nrows; i++) {
delete [] ETS[i];
}
delete [] ETS;
I good rule is that for each call to new you have to call delete; You allocate the array with nrows+1 calls to new so you have to delete with the same number. That's not hard and fast but it'll clue you in when something is going wrong.
The common way to implement binary arithmetic operators is to define operator+= as a class member function and operator+ as a free-standing function. Note the + operator is implemented in terms of the += operator and it takes its left operand by copy. As long as your copy constructor and assignment operator are correct this should work.
// member function
Mtx& Mtx::operator+=(const Mtx &rhs)
{
for (int i = 0; i < nrows; ++i) {
for (int j = 0; j < ncols; ++i) {
ets[i][j] += rhs.ets[i][j];
}
}
return *this;
}
// non-member function
Mtx operator+(Mtx lhs, const Mtx &rhs)
{
lhs += rhs;
return lhs;
}
Related
A great deal of unexpected numbers outputted on my console window when I compiled and ran the program.
The class "matrix" is declared as below:
class matrix
{
public:
vector<vector<int> > M;
matrix();
matrix(int m, int n);
matrix(vector<vector<int> > &m);
matrix Mul(matrix m1);
void Inverse();
bool SquareMatrix();
void GetDet();
int Det(vector<vector<int> > &m);
void Print();
};
the member function "Mul":
matrix matrix::Mul(matrix m1)
{
vector<vector<int> > Temp(M.size(), vector<int>(m1.M[0].size(), 0));
if (M[0].size() != m1.M.size())
{
cout << "Cannot do multiplication!" << endl;
return matrix();
}
else
{
for (int i = 0; i < M.size(); i++)
{
for (int j = 0; j < m1.M[0].size(); j++)
{
int ele_buf = 0;
for (int k = 0; k < M[0].size(); k++)
{
ele_buf += M[i][k] * m1.M[k][j];
}
Temp[i][j] = ele_buf;
}
}
}
int d1 = M.size(), d2 = m1.M[0].size();
for (int i = 0; i < M.size(); i++)
{
M[i].clear();
}
M.clear();
M.resize(Temp.size(), vector<int>(Temp[0].size(), 0));
for (int i = 0; i < d1; i++)
{
for (int j = 0; j < d2; j++)
{
M[i][j] = Temp[i][j];
}
}
}
M[i][j] hold the expected value at this point.
the member function "Print":
void matrix::Print()
{
for (int i = 0; i < M.size(); i++) {
for (int j = 0; j < M[0].size(); j++) {
cout << M[i][j] << " ";
}
cout << endl;
}
}
Output wrong M.
main:
/*
call constructor to initialize m1 and m2
*/
//...
matrix m3 = m1.Mul(m2);
m3.Print();
//...
How can I fix it?
I'm new here, plz let me know if I didn't make my question clear.
Editted:
matrix matrix::Mul(matrix m1)
{
vector<vector<int> > Temp(M.size(), vector<int>(m1.M[0].size(), 0));
if (M[0].size() != m1.M.size())
{
cout << "Cannot do multiplication!" << endl;
return matrix();
}
else
{
//TO_DO: Multiply two matrixes and print the result.
for (int i = 0; i < M.size(); i++)
{
for (int j = 0; j < m1.M[0].size(); j++)
{
int ele_buf = 0;
for (int k = 0; k < M[0].size(); k++)
{
ele_buf += M[i][k] * m1.M[k][j];
}
Temp[i][j] = ele_buf;
}
}
}
int d1 = M.size(), d2 = m1.M[0].size();
for (int i = 0; i < M.size(); i++)
{
M[i].clear();
}
M.clear();
return matrix(Temp);
}
Functionning properly,
thanks.
You forgot to add a return statement, which is trivial to fix. However, your code is not written in a good OO manner, so here come few suggestions for the improvement:
don't pass matrix m1 by value, because you are paying an expensive copy each time you invoke this function; use const matrix& m1 instead
in the body of Mul you are modifying member M, which is a serious side effect; remove the part of code:
int d1 = M.size(), d2 = m1.M[0].size();
for (int i = 0; i < M.size(); i++)
{
M[i].clear();
}
M.clear();
instead of implementing a separate function called Mul, overload the * operator (see e.g. here and here)
You are promised to return matrix from the Mul function
matrix matrix::Mul(matrix m1);
^^^^^^
and you did not keep the promise. This can cause undefined behaviour to your program.
Add an proper return statement in the function.
matrix matrix::Mul(matrix m1)
{
// ... code
return *this; // matrix(Temp) itself
}
#include <iostream>
using namespace std;
class Matrix {
public:
long int **Matr;
long int n;
void Create() {
Matr = new long int *[n];
for (int z = 0; z < n; z++)
Matr[z] = new long int[n];
}
// constructors and destructor
Matrix() : n(5) { Create(); }
Matrix(long int i) : n(i) { Create(); }
// Copy constructor
Matrix(Matrix &N) {
n = N.n;
Matr = new long int *[n];
for (int i = 0; i < n; i++)
Matr[i] = new long int[n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
Matr[i][j] = N.Matr[i][j];
}
}
}
Matrix operator*(Matrix &mx) {
int i, j, k, num;
Matrix result(n);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
num = 0;
for (int k = 0; k < n; k++) {
num += Matr[i][k] * mx.Matr[k][j];
}
result.Matr[i][j] = num;
return result;
}
~Matrix() {
for (int z = 0; z < n; z++) {
delete[] Matr[z];
}
delete[] Matr;
}
void Display() {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cout << Matr[i][j];
}
cout << endl;
}
}
Matrix operator+(Matrix &mx) {
Matrix result(n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
result.Matr[i][j] = Matr[i][j] + mx.Matr[i][j];
// cout << result.Matr[i][j] << "\n";
}
}
return result;
}
};
int main() {
Matrix M(2);
M.Matr[0][0] = 0;
M.Matr[0][1] = 1;
M.Matr[1][0] = 2;
M.Matr[1][1] = 3;
Matrix N(2);
N.Matr[0][0] = 0;
N.Matr[0][1] = 1;
N.Matr[1][0] = 2;
N.Matr[1][1] = 3;
Matrix C;
C = M + N;
cout << C.Matr[0][0];
return 0;
}
I am doing a Matrix OOP class with some basic methods. I can't do "+" operator work in the way I want. In this case, when I'm trying to print C.Matr[0][0] it's printing random number for some reason, but if I simply remove destructor from code it works as expected and printing 0. Can someone help me to figure out why this is happening? Thanks a lot.
C is assigned a temporary with a shared Matr. The temporary dies immediately and you delete dangling pointers in the dtor.
The rule of three/five/zero will help you to prevent it.
What you are missing a copy assignment operator:
Matrix& operator=(const Matrix& N)
{
// copy to temporary matrix
long int tmpN = N.n;
long int** tmpMatr = new long int*[tmpN];
for (int i = 0; i < tmpN; i++)
tmpMatr[i] = new long int[tmpN];
for (int i = 0; i < tmpN; i++)
{
for (int j = 0; j < tmpN; j++)
tmpMatr[i][j] = N.Matr[i][j];
}
// swap
long int** swapMatr = Matr;
long int swapN = n;
Matr = tmpMatr;
n = N.n;
// deallocate old Matr
for (int z = 0; z<swapN; z++){
delete[] swapMatr[z];
}
delete[] swapMatr;
return *this;
}
Online gdb
You must implement the assignment operator, not just the copy constructor and destructor.
The simplest way to implement the assignment operator is to use the copy / swap idiom:
#include <algorithm>
//...
class Matrix
{
//...
int **Matr;
int n;
//...
public:
Matrix& operator=(const Matrix& m)
{
if ( this != &m )
{
Matrix temp(m); // create a copy of the passed in value
std::swap(temp.Matr, Matr); // swap out the internals with *this
std::swap(temp.n, n);
} // Here temp's destructor removes the old memory that *this
// previously had
return *this;
}
//...
};
Note that this only works if you have a working, non-buggy copy constructor and destructor.
In addition, your copy constructor should be taking a const reference, not just a reference to Matrix:
Matrix(const Matrix& m) { ... }
Once you make those changes, the program no longer crashes, as seen here.
You don't have an assignment operator, so who knows what the line C = M + N; is doing?
Well, it's using the default assignment operator, which just copies each member in turn. In particular, the pointer Matr is copied from the pointer in the temporary M+N, so it points to memory which was allocated for the temporary, which is then destroyed.
Before you added the destructor, you had a memory leak, so the values persisted in the heap, and it appeared to work. After you added a destructor which freed the memory, it was apparently quickly overwritten.
I am new to c++ and I have to create a 2D array using pointers. I have completed the creation of the array but I cannot run anything after the initial creation of the matrix due to a "Segmentation fault". I believe this is from my assignment operator, but I'm not sure. This could be from the copy constructor, but because we have to use pointers I am lost. Any help would be appreciated.
#ifndef My_Matrix_H
#define My_matrix_H
#include "My_matrix.h"
#include <stdexcept>
My_matrix::My_matrix() //contructor
{
n = 0;
m = 0;
ptr = NULL;
}
My_matrix::My_matrix(int n1, int m1) //creation of the matrix
{
ptr = new int*[n1];
for (int i = 0; i < n1; i++)
{
ptr[i] = new int[m1];
for (int j = 0; j < m1; j++)
{
ptr[i][j] = 0;
}
}
}
My_matrix::My_matrix(const My_matrix& mat) //copy constructor
{
n = mat.n;
m = mat.m;
ptr = new int*[n];
for (int i = 0; i < n; i++)
{
ptr[i] = new int[m];
for (int j = 0; j < m; j++)
{
ptr[i][j] = mat.ptr[i][j];
}
}
}
My_matrix::~My_matrix() //destructor
{
for (int i = 0; i < n; i++)
{
delete[] ptr[i];
}
delete[] ptr;
}
My_matrix& My_matrix::operator=(const My_matrix& mat) //assignmemt operator
{
n = mat.n;
m = mat.m;
ptr = new int*[n];
cout << "1" << endl;
for (int i = 0; i < n; i++)
{
cout << "2" << endl;
ptr[i] = new int[m];
for (int j = 0; j < m; j++)
{
cout << "3" << endl;
ptr[i][j] = mat.ptr[i][j];
}
}
}
void My_matrix::elemset(int i, int j, int num) //puts stuff into matrix
{
ptr[i][j] = num;
}
}#endif
[1] In My_matrix(int,int) members n and m are not set (this is cause of all troubles, if you call any of these members (copy constructor, assignment operator or destructor) after creating object by My_matrix(int,int) without setting n,m, your application must crash).
[2] My_matrix::operator= should return *this.
[3] In My_matrix::operator= you should delete previous allocated data.
For the answer. A copy/swap was most effective, as given by #PaulMcKenzie.
My_matrix& My_matrix::operator=(const My_matrix& mat)
{
My_matrix temp(mat);
std::swap(n,temp.n);
std::swap(m, temp.m);
std::swap(ptr, temp.ptr);
return *this;
}
i am working on multiplication of matrix
it is something like
m5 = m2 * m3;
cout << "m2 * m3 is : " << endl<< m5 << endl;
and this is my code
const Matrix Matrix::operator*(const Matrix &a)
{
Matrix temp(a.row,a.col);
for (int i = 0; i<row; i++)
{
for (int j = 0; j<col; j++)
{
for (int k = 0; k<a.row; k++)
{
temp.data[i][j] = temp.data[i][j] + data[i][k] * a.data[k][j];
}
}
}
return temp;
}
However, there is an error always showing at my printing function
ostream& operator<<(ostream &output, const Matrix &a)
{
for (int i = 0; i < a.row; i++)
{
for (int j = 0; j < a.col; j++)
{
output << a.data[i][j] << "\t";
}
output << "" << endl;
}
return output;
}
seems there has a problem on a.data[i][j] which i dont know what's the problem
it works fine on addition.
it is showing an error {data0x005fba90{0xfeeefeee{???}}
can anybody give any advice or suggestions or help on this situation
this is my copy constructor
Matrix::Matrix(const Matrix&m2)
{
row = m2.row;
col = m2.col;
setUp(row, col);
for (int i = 0; i<row; i++)
{
for (int j = 0; j<col; j++)
{
data[i][j] = 0;
}
}
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
data[i][j] = m2.data[i][j];
}
}
}
this is the set up and default
Matrix::Matrix()
{
row =0;
col = 0;
for (int i = 0; i<row; i++)
{
for (int j = 0; j<col; j++)
{
data[i][j] = 0;
}
}
}
Matrix::Matrix(int a, int b, double d[], int c)
{
row = a;
col = b;
setUp(row, col);
int counter = 0;
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
data[i][j] = d[counter];
counter++;
}
}
}
and the set up
void Matrix::setUp(int a, int b)
{
row = a;
col = b;
data = new double*[row];
for (int i = 0; i < row; i++) data[i] = new double[col];
}
Without seeing your Matrix constructor, or the class definition, it's hard to say for certain, but if you look at this expression
temp.data[i][j] + data[i][k] * a.data[k][j]
Depending on what data is, if you don't explicitly initialize the data member in the constructor when you create temp then its contents will not automatically be initialized, and the contents will be indeterminate and using it will lead to undefined behavior.
Another possible source of problems might be the lack of a copy-constructor, or a faulty copy-constructor. This is a problem since you return temp by value which invokes the copy-constructor.
I'm trying to overload the + operator for a project that I'm doing but this keeps on happening. I think the reason is that the object I created is getting deleted when the operator is getting invoked. Not sure how to fix it though. Here's part of my code:
Matrix Matrix::operator+ (const Matrix& m) const
{
//something wrong here
Matrix sum(rows, cols);
for (int i = 0; i < cols; i++)
{
for (int j = 0; j < rows; j++)
{
sum.element[i][j] = this->element[i][j] + m.element[i][j];
}
}
return sum;
}
Additional Information
Matrix::Matrix(int r, int c)
{
rows = r;
cols = c;
element = new int *[c];
for (int i = 0; i < c; i++)
{
element[i] = new int[r];
}
for (int i = 0; i < cols; i++)
{
for (int j = 0; j < rows; j++)
{
element[i][j] = 0;
}
}
}
Matrix::Matrix(const Matrix& m)
{
this->element = m.element;
}
Matrix::~Matrix()
{
//freeing up the arrays
for (int i = 0; i < cols; i++)
{
delete[] element[i];
element[i] = NULL;
}
delete[] element;
element = NULL;
}
Matrix& Matrix::operator= (const Matrix& m)
{
//problem if rows and cols are longer in the new matrix
//need to create a temp matrix to expand to new one
for (int i = 0; i < cols; i++)
{
for (int j = 0; j < rows; j++)
{
this->element[i][j] = m.element[i][j];
}
}
return *this;
}
int* Matrix::operator[] (int n)
{
return element[n];
}
The specific error I am getting is:
Debug Assertion Failed!
Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
In line 52 which I did this:
Matrix total = mat + m;
Where mat and m are both object matrices
I'm guessing the problem is caused by this:
Matrix::Matrix(const Matrix& m)
{
this->element = m.element;
}
That is an invalid copy constructor for two reasons. First, you're not initializing rows or cols. Second, you'll now have two Matrix objects pointing to the same memory - both of which will delete it on destruction:
{
Matrix m1(3, 5);
Matrix m2 = m1;
} // BOOM!
You need to do a deep copy here:
Matrix::Matrix(const Matrix& m)
: rows(m.rows), cols(m.cols)
{
element = new int *[cols];
for (int i = 0; i < cols; ++i) {
element[i] = new int[rows];
for (int j = 0; j < rows; ++j) {
element[i][j] = m.element[i][j];
}
}
}