Vector values not saved permanently [C++ Rookie] - c++

I overwrote a + operator:
Matrix& Matrix::operator+(Matrix m1)
{
//This should never be triggered
if(this->data.capacity() != m1.data.capacity() || this->data[0].capacity() != m1.data[0].capacity())
{
cout << "Dimensions don't match, can't add.\n";
throw 7;
}
vector<vector<double>> result;
result.resize(m1.data.capacity());
for(int i = 0; i < m1.data.size(); i++)
{
result[i].resize(m1.data[0].size());
for(int j = 0; j < m1.data[0].size(); j++)
{
result[i][j] = m1.data[i][j] + this->data[i][j];
}
}
return Matrix(m1.getRows(),m1.getCols(), result);
}
This is the corresponding Constructor:
Matrix::Matrix(int rows, int cols, vector<vector<double>> data)
{
this->rows = rows;
this->cols = cols;
this->data = data;
}
Here's the executing code:
c = (a+b);
When I assign a breakpoint at the last line of the operator overload, I can see the correct results in result and both cols and rows are assigned correctly. When I step out, c has "rows" and "cols" set correctly, but data is empty. Why is that?

Your operator + is wrong. It should be returning a new object, not a reference to a local object (which is UB anyway).

Related

C++ Access violation reading location 0xCCCCCCBC [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I'm writing a program that implements some functions of matrix but get into trouble at the beginning stage.
When debugging goes to c = c.transpose(); in the main function,it steps into the copy constructor and throws an exception at the statement:delete[]elements;. And it says:
Unhandled exception at 0x7CBDDB1B (ucrtbased.dll) in Exercise2.2.exe: 0xC0000005: Access violation reading location 0xCCCCCCBC.
I have no idea what happens. I would appreciate it if someone could take a look at my code.
Btw, I'm a C++ beginner, so besides the error, if there are codes that are not of standard, please point it out.
header:
#include <iostream>
using namespace std;
class Matrix
{
int row;
int col;
double **elements;
public:
Matrix();
Matrix(int row, int col);
Matrix(const Matrix& srcMatrix);
Matrix& operator=(const Matrix& srcMatrix);
void setNum(double Num, int row,int col);
Matrix transpose();
void display();
};
Matrix::Matrix():elements(0),row(0),col(0){}
Matrix::Matrix(int row, int col) :row(row), col(col) {
elements = new double*[row];
for (int i = 0;i < row;i++) {
elements[i] = new double[col];
}
}
Matrix::Matrix(const Matrix& srcMatrix){
row == srcMatrix.row;
col == srcMatrix.col;
if (elements != NULL) {
delete[]elements;
}
elements = new double* [row];
for (int i = 0;i < row;i++) {
elements[i] = new double[col];
}
for (int i = 0;i < row;i++) {
for(int j = 0;j < col;j++) {
elements[i][j] = srcMatrix.elements[i][j];
}
}
}
Matrix& Matrix::operator=(const Matrix& srcMatrix) {
row == srcMatrix.row;
col == srcMatrix.col;
if (elements != NULL) {
delete[]elements;
}
elements = new double* [row];
for (int i = 0;i < row;i++) {
elements[i] = new double[col];
}
for (int i = 0;i < row;i++) {
for (int j = 0;j < col;j++) {
elements[i][j] = srcMatrix.elements[i][j];
}
}
return *this;
}
void Matrix::setNum(double Num, int row, int col) {
elements[row][col] = Num;
}
Matrix Matrix::transpose() {
Matrix temp(col,row);
for (int i = 0;i < row;i++) {
for (int j = 0;j < col;j++) {
temp.elements[j][i] = elements[i][j];
}
}
return temp;
}
void Matrix::display() {
for (int i = 0;i < row;i++) {
for (int j = 0;j < col;j++) {
cout << elements[i][j] << " ";
if (j == col - 1) {
cout << endl;
}
}
}
}
Main function:
#include<iostream>
#include "Matrix.h"
using namespace std;
int main(){
double a[3] ={ 1.0,3.0,2.0 };
double b[3] ={ 2.0,3.0,4.0 };
Matrix c(2,3);
for (int i = 0;i < 3;i++) {
c.setNum(a[i], 0, i);
c.setNum(b[i], 1, i);
}
c = c.transpose();
c.display();
return 0;
}
Matrix::Matrix(const Matrix& srcMatrix){
...
if (elements != NULL) {
delete[]elements;
}
You never initialised elements in this constructor. You leave it with indeterminate value, but read its value when comparing to null, and then attempt to delete it, both of which result in undefined behaviour.
You are constructing a new object. It cannot possibly own any elements before you create them, so there is nothing to delete either.
row == srcMatrix.row;
col == srcMatrix.col;
These comparisons, and later use as array size also read members whose values are indeterminate due to lack of initialisation. I suspect that you instead intended to assign the members. Assignment operator is single = not two. That said, it's better to initialise the members instead of assigning later.
Also, unless you need to support ancient compilers, use nullptr instead of NULL. Also, if you use NULL, you should include the header which defines it.
Your copy and constructor and operator=are deleting an unitialised variable. There is no need to delete elements in any case as it has never been allocated in the first instance - you do that later.
Remove the part:
if (elements != NULL) {
delete[]elements;
}
from both. Or better since your copy constructor and operator= contain identical code, create a copy function and use that from both. The operator= should also have a self assignment check so that expressions such as x = x are safe:
Matrix::Matrix(const Matrix& srcMatrix)
{
this->copy( srcMatrix ) ;
}
Matrix& Matrix::operator=(const Matrix& srcMatrix)
{
if( this != &srcMatrix ) this->copy( srcMatrix ) ;
return *this
}

Using 2 overloaded operators in one command cause an error

I was creating a matrix class with overloaded operators in C++, I overloaded operators, << (output, with the ostream library), operator + that adds to matrices, operator = that's is used to assign one matrix to another. The problem is that when I use
cout<<m1+m2<<endl;
I get an error
E0349: No operator << matches these operands type are: std::ostream << Matrix
But if i do the following:
Matrix m = m1 + m2;
cout<<m<<endl;
it works perfect.
Here is the << operator:
ostream& operator<< (ostream &os,const Matrix& m)
{
if (m.isValid())
{
os << '|';
for (int i = 0; i < m.getRows(); i++)
{
for (int j = 0; j < m.getCols(); j++)
{
os << m.getMatrix()[i][j];
if (j < m.getCols() - 1)
{
os << ',';
}
}
os << '|';
}
}
else
{
os << "invalid matrix!";
}
return os;
}
The + operator:
Matrix Matrix::operator+ (Matrix &m)
{
Matrix* answer = new Matrix(m); //allocating space
if (valid && m.valid)//if they are both valid
{
if (colNum == m.colNum&&rowNum == m.rowNum) //if are from same size
{
answer->valid = true; //valid set to be true
for (int i = 0; i < rowNum; i++) //going over the matrix
{
for (int j = 0; j < colNum; j++)
{
answer->matrix[i][j] += matrix[i][j]; //adding data
}
}
}
else
{
//clearing data
delete answer;
answer = new Matrix();
}
}
else
{
//clearing data
delete answer;
answer = new Matrix();
}
return *answer;
}
And the = operator:
Matrix Matrix::operator= (Matrix &m)
{
int rows = m.rowNum; //putting cols and rows from the data
int cols = m.colNum;
if (m.valid)
{
matrix = new int*[rows]; //defining the matrix - first allocatin space for rows
for (int i = 0; i < rows; i++) //now allocating space for cols
{
matrix[i] = new int[cols];
}
for (int i = 0; i < rows; i++) //now going over the matrix and putting the data in
{
for (int j = 0; j < cols; j++)
{
matrix[i][j] = m.matrix[i][j];
}
}
}
//putting the rows and cols data
rowNum = m.rowNum;
colNum = m.colNum;
valid = m.valid; //setting to the right valid type
return *this;
}
and the class variables:
class Matrix
{
private:
bool valid;
int** matrix;
int rowNum;
int colNum;
There is a copy constructor a string constructor and a constructor that gets string input according to an algorithm and transforms it to a matrix.
You are actually faced with the fact that you Can't pass temporary object as reference (the link is to another question here on StackOverflow).
The solution in your case should be to replace:
ostream& operator<< (ostream &os,Matrix& m)
with:
ostream& operator<< (ostream &os,const Matrix& m)
as the overloaded operator signature. You currently expects an lvalue reference, In the case of
Matrix m = m1 + m2;
cout << m << endl;
that is what you're calling the function with m - a named variable and will outlive the execution of the command. In the failing case, you're calling the function with m1+m2 - the result of a plus operation, which is a temporary object. It just doesn't match your overload.
By the way - this change also makes sense because you're not modifying the matrix as you print it - you treat it as const.

Incorrect output from overloaded [] function

The spec says that the function must return the row of the matrix specified by the "row number" in []
Class Definition:
class Matrix
{
public:
//functions taken out
private:
double ** matrix; // the matrix array
unsigned rows; // # rows
unsigned cols; // # columns
};
The brief main:
cout << "Test []: " << endl;
try {
Matrix row = m0[0]; //**m0 is Matrix m0(1,1); where the constructor creates the appropriate array**
cout << row << endl;
row = m0[1];
cout << row << endl;
row = m0[100]; // should throw an exception
} catch (const char * err) {
cout << err << endl;
}
The Function implementation:
double& Matrix::operator [](const unsigned int &sub)
{
if( sub >= rows)
{
const char * error = "Error: invalid row index";
throw error;
} else
{
return *matrix[sub];
}
}
Overloaded << operator for display:
//This is working for my other displays so this shouldn't be the problem
ostream &operator << (ostream &ostrm, const Matrix &obj)
{
//Loop through to display
for(unsigned int i = 0; i < obj.rows; i++)
{
for(unsigned int j = 0; j< obj.cols; j++)
{
ostrm << setw(10) << setprecision(3) << obj.matrix[i][j];
}
ostrm << endl;
}
return ostrm;
}
Overloaded = operator:
//Again this works for everything else
Matrix& Matrix::operator=(const Matrix &rhs)
{
//Copy Rows and Cols
rows = rhs.rows;
cols = rhs.cols;
//If statement to check for self assignment
if(&rhs == this)
{
return *this;
}
else
{
delete [] matrix;
matrix = new double*[rows]; //Allocate Dynamic Array
//Deep copy elements by looping and copying each element
for(unsigned int i = 0; i < rows; i++)
{
matrix[i] = new double[cols];
for(unsigned int j = 0; j < cols; j++)
{
matrix[i][j] = rhs.matrix[i][j];
}
}
return *this;
}
}
My Output:
Test []:
Error: invalid row index
Expected Output:
Test []:
17.2 -3 -0.5 6
8.2 4 3 1
Error: invalid row index
I am uncertain as to why the rows are not displaying or possibly not even being stored.
Thanks in advance
Aside comment: your assignment operator is leaking memory: you delete matrix, but you need to delete also the individual rows (using the original value of rows)
for(unsigned int i = 0; i < rows; i++)
delete[] matrix[i];
Your operator[] should return a double[] or double *, not a double - you want to return a whole row, not a single value.
Your "test []" code should not even compile... Matrix row = m0[0]; assigns a double to a Matrix object.
Etc.
Bottom line: just use Eigen.
The first line is wrong.
operator[] is returning a double. You assign it to a Matrix. The Matrix is initialized with one value. You've taken out your Constructors. Which one is called? I assume, the called constructor initializes the rows and cols members with zero. When they're zero, the output stream operator does nothing.
I managed to find a solution that worked for my question. Below is what I implemented in case someone else has a similar problem.
Matrix temp(1, cols); //Calls my constructor here
for(unsigned int i = 0; i < 1; i++)
{
for(unsigned int j = 0; j < cols; j++)
{
temp.matrix[i][j] = matrix[sub][j]; //Accessed temp's matrix and assigned it with what is in the matrix that called the function
}
}
return temp;
Thank you to everyone who helped and added some input. Much appreciated

copy constructor error: the object has type qualifiers that are not compatible with the member function

im working with simple 2D array,but in my copy constructor i encounter a problem.
Here's a excerpt from my code:
//default constructor
Matrix::Matrix(int r, int c)
{
rows = r;
cols = c;
mainArray = new int[rows*cols];
array = new int *[rows];
for (int i = 0; i < rows; i++)
array[i] = mainArray + (i*cols);
}
//at member
int& Matrix::at(int i, int j)
{
return array[i][j];
}
//copy constructor
Matrix::Matrix(const Matrix & obj)
{
rows = obj.rows;
cols = obj.cols;
mainArray = new int[rows*cols];
array = new int *[rows];
for (int i = 0; i < rows; i++)
array[i] = mainArray + (i*cols);
}
for (int i = 0; i < obj.rows; i++)
{
for (int j = 0; j < obj.cols; j++)
at(i, j) =obj.at(i,j);//PROBLEM
}
}
when im trying to assign at(i,j)=obj.at(i,j) i get this:
the object has type qualifiers that are not compatible with the member function
as far as i know, copy constructor is supposed to be passed by (const class& obj).
what should i do?
That's because your copy constructor take a const parameter, and your method Matrix::at is not const.
I suggest you to do two versions of your at method, one const and one not :
// Use for assignement
int& Matrix::at(int i, int j)
{
return array[i][j];
}
// Use for reading
int Matrix::at(int i, int j) const
{
return array[i][j];
}
Your compiler should know in which case call which one without your help, depending if you are trying to modify or just read your instance :
Matrix matrix(4, 4);
matrix.at(1, 2) = 42; // Assignement method called
int i = matrix.at(1, 2); // Read method called
Realize two versions of at function, one const and one non-const.
int& Matrix::at(int i, int j)
{
return array[i][j];
}
int Matrix::at(int i, int j) const
{
return array[i][j];
}

Huge deletion error using C++ classes

I'm building an image analysing program in c++. It takes in a text file which holds the values to build a grey scale image. I am using the sum of squared differences to find a specific block in this image.. This is built using a matrix class in a header file so I have two overloaded constructors and a destructor which deletes the pointer to the double which allocates memory on the heap for this huge array of values (768 x 1024). This however throws out a memory error; Debug assertion failed, expression: block type is valid. I can't fathom why this is happening.. To do the SSD calculation I use two for loops; two matrix objects are manipulated one of these amendments calls one of the constructors to create a new matrix object from the getting a block from a larger matrix object. I understand that the destructor is called twice through every loop as the objects go out of scope? Is this double deletion and why the error occurs? Below are my constructors and the loops. If anyone can see why I'm getting this error I'd be very happy.
Constructors:
// Matrix constructor creating a new matrix object where all elements are the same number
Matrix::Matrix(int sizeR, int sizeC, double val)
{
//cout << "Matrix(int sizeR, int sizeC, double val) is invoked.." << endl;
M = sizeR;
N = sizeC;
data = new double[M * N];// Initialise space for class array 'data'
for (int i = 0; i < M* N; i++)
{
data[i] = val;// Set each element of the array to the same value passed to the constructor from main
}
}
// Matrix constructor taking pointer to array as input; creates a new matrix object
Matrix::Matrix(int sizeR, int sizeC, double* input_data)
{
//cout << "Matrix::Matrix(int sizeR, int sizeC, double* input_data) is invoked...." << endl;
M = sizeR;
N = sizeC;
data = new double[M * N];// Initialise space for class array 'data'
for (int i = 0; i < M * N; i++)
{
data[i] = input_data[i];// Set elements in data as elements from input_data passed to the constructor from main
}
}
Destructor:
// Matrix destructor
Matrix::~Matrix()
{
//cout << "Matrix::~Matrix() is invoked..." << endl;
delete data;
}
Code in main:
for (int i = 0; i < (768 - 21); i++)
{
for (int j = 0; j < (1024 - 21); j++)
{
counter++;
clutteredBlock = cluttered.getBlock(i, (i + 21), j, (j + 21));
diff = clutteredBlock - wallyBlock;
diff = diff * diff;
tempVal = diff.Sum();
if (i == 0 && j == 0)
{
ssd = tempVal;
}
if (tempVal <= ssd)
{
ssd = tempVal;
co1 = i;
co2 = j;
}
}
}
So M, N and data are all private class members; M and N are int and data is a double*; data being the pointer I'm trying to delete and getting nowhere with.
UPDATE: If I ignore the error I am then given a HEAP CORRUPTION error saying that I am trying to write to the heap after the buffer?
UPDATE: Assignment Operator;
Matrix& Matrix::operator=(const Matrix& input)
{
//cout << "Matrix::operator= is invoked..." << endl;
if (this == &input)
{
return *this;
}
else
{
delete data;
M = input.getR();
N = input.getC();
data = new double[M * N];
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
Set(i, j, input.Get(i, j));
}
}
}
return *this;
}
Any input is greatly appreciated :)
Use a std::vector for your storage. It handles allocation and deallocation automatically. Problem solved.