I am working on a Matrix class for a CS project, and I'm trying to work on the constructors. The project calls for two different constructors, one just calling out the numbers of rows and columns and making them all 0 and another using an initializer list to assign the values. The header file so far is:
typedef unsigned int uint;
typedef std::initializer_list<std::initializer_list<double>> i_list;
class Matrix {
public:
double ** arr;
uint mainRows;
uint mainCols;
Matrix(uint rows, uint cols);
Matrix(const i_list & list);
Matrix(const Matrix & m);
~Matrix();
};
Some of the test cases require you to both define the rows and use the initializer list, for example:
Matrix d(2,2);
d = {{1,2},{3,4}};
But I noticed that every time I try and run this kind of code, the destructor will immediately delete the double ** arr which is where the values for the Matrix's are stored. Here is the code for the constructors:
Matrix::Matrix(uint rows, uint cols)
{
mainRows = rows;
mainCols = cols;
arr = new double*[rows];
for (int i = 0; i < mainRows; i++) {
arr[i] = new double[cols];
}
for (int i = 0; i < mainRows; i++) {
for (int j = 0; j < mainCols; j++) {
arr[i][j] = 0;
}
}
}
Matrix::Matrix(const i_list & list)
{
int i = 0, j = 0;
mainRows = list.size();
mainCols = (*list.begin()).size();
arr = new double*[mainRows];
for (std::initializer_list<double> I : list) {
j = 0;
arr[i] = new double[mainCols];
for (double d : I) {
arr[i][j] = d;
j++;
}
i++;
}
}
Matrix::Matrix(const Matrix & m)
{
this->arr = m.arr;
this->mainRows = m.mainRows;
this->mainCols = m.mainCols;
for (uint i = 0; i < mainRows; i++) {
for (uint j = 0; j < mainCols; j++) {
this->arr[i][j] = m.arr[i][j];
}
}
}
Matrix::~Matrix()
{
for (uint i = 0; i < mainRows; i++) {
delete[] arr[i];
}
delete[] arr;
}
I guess since its calling a constructor for the same object twice it's creating two double ** ars and that's why the Destructor want's to delete the original, but then I can't call on the values for other functions. Can somebody help me out with what I'm doing wrong?
The problem is that your copy-constructor only copies the pointer of the source object, not allocates new memory.
This is problematic because
d = {{1,2},{3,4}};
creates a temporary object out of {{1,2},{3,4}}. You statement is actually equal to
d = Matrix({{1,2},{3,4}});
which is equal to
d.operator=(Matrix({{1,2},{3,4}}));
After the assignment is made, you have two objects pointing to the same memory for arr. And then the temporary object is destructed, leading to arr inside d to become invalid, as it no longer points to allocated memory.
The naive solution is simple: Allocate memory for arr to point to in the copy-constructor. The better solution is to stop using pointers and dynamic allocation, and instead use std::vector, and live by the rule of zero, where you don't need any copy-constructor, no copy-assignment operator and no destructor.
This is wrong:
Matrix::Matrix(const Matrix & m)
{
this->arr = m.arr;
this->mainRows = m.mainRows;
this->mainCols = m.mainCols;
for (uint i = 0; i < mainRows; i++) {
for (uint j = 0; j < mainCols; j++) {
this->arr[i][j] = m.arr[i][j];
}
}
}
Note yuo do not creating actual copy here. this->arr = m.arr; makes both pointers to pointing same part of memory so new and old instance of Matrix are sharing this memory. So flowing for loops does nothing.
Than when one of instances is destroyed the other instance is pointing to memory which is freed.
Related
I am trying to do a large matrix multiplication, e.g. 1000x1000. Unfortunately, it only works for very small matrices. For the big ones, the program just turns on and that's all - no results. Here's the code:
#include <iostream>
using namespace std;
int main() {
int matrix_1_row;
int matrix_1_column;
matrix_1_row = 10;
matrix_1_column = 10;
int** array_1 = new int* [matrix_1_row];
// dynamically allocate memory of size matrix_1_column for each row
for (int i = 0; i < matrix_1_row; i++)
{
array_1[i] = new int[matrix_1_column];
}
// assign values to allocated memory
for (int i = 0; i < matrix_1_row; i++)
{
for (int j = 0; j < matrix_1_column; j++)
{
array_1[i][j] = 3;
}
}
int matrix_2_row;
int matrix_2_column;
matrix_2_row = 10;
matrix_2_column = 10;
// dynamically create array of pointers of size matrix_2_row
int** array_2 = new int* [matrix_2_row];
// dynamically allocate memory of size matrix_2_column for each row
for (int i = 0; i < matrix_2_row; i++)
{
array_2[i] = new int[matrix_2_column];
}
// assign values to allocated memory
for (int i = 0; i < matrix_2_row; i++)
{
for (int j = 0; j < matrix_2_column; j++)
{
array_2[i][j] = 2;
}
}
// Result
int result_row = matrix_1_row;
int result_column = matrix_2_column;
// dynamically create array of pointers of size result_row
int** array_3 = new int* [result_row];
// dynamically allocate memory of size result_column for each row
for (int i = 0; i < result_row; i++)
{
array_3[i] = new int[result_column];
}
// Matrix multiplication
for (int i = 0; i < matrix_1_row; i++)
{
for (int j = 0; j < matrix_2_column; j++)
{
array_3[i][j] = 0;
for (int k = 0; k < matrix_1_column; k++)
{
array_3[i][j] += array_1[i][k] * array_2[k][j];
}
}
}
//RESULTS
for (int i = 0; i < result_row; i++)
{
for (int j = 0; j < result_column; j++)
{
std::cout << array_3[i][j] << "\t";
}
}
// deallocate memory using delete[] operator 1st matrix
for (int i = 0; i < matrix_1_row; i++)
{
delete[] array_1[i];
}
delete[] array_1;
// deallocate memory using delete[] operator 2nd matrix
for (int i = 0; i < matrix_2_row; i++)
{
delete[] array_2[i];
}
delete[] array_2;
// deallocate memory using delete[] operator result
for (int i = 0; i < result_row; i++)
{
delete[] array_3[i];
}
delete[] array_3;
return 0;
}
Anyone have an idea how to fix it? At what point did I go wrong? I used pointers, dynamic memory allocation.
Instead of working with arrays directly named as matrix, try something simple and scalable, then optimize. Something like this:
class matrix
{
private:
// sub-matrices
std::shared_ptr<matrix> c11;
std::shared_ptr<matrix> c12;
std::shared_ptr<matrix> c21;
std::shared_ptr<matrix> c22;
// properties
const int n;
const int depth;
const int maxDepth;
// this should be shared-ptr too. Too lazy.
int data[16]; // lowest level matrix = 4x4 without sub matrix
// multiplication memory
std::shared_ptr<std::vector<matrix>> m;
public:
matrix(const int nP=4,const int depthP=0,const int maxDepthP=1):
n(nP),depth(depthP),maxDepth(maxDepthP)
{
if(depth<maxDepth)
{
// allocate c11,c22,c21,c22
// allocate m1,m2,m3,...m7
}
}
// matrix-matrix multiplication
matrix operator * (const matrix & mat)
{
// allocate result
// multiply
if(depth!=maxDepth)
{
// Strassen's multiplication algorithm
*m[0] = (*c11 + *c22) * (*mat.c11 + *mat.c22);
...
*m[6] = (*c12 - *c22) * (*mat.c21 + *mat.c22);
*c11 = *m[0] + *m[3] - *m[4] + *m[6];
..
*c22 = ..
}
else
{
// innermost submatrices (4x4) multiplied normally
result.data[0] = data[0]*mat.data[0] + ....
...
result.data[15]= ...
}
return result;
}
// matrix-matrix adder
matrix operator + (const matrix & mat)
{
// allocate result
// add
if(depth!=maxDepth)
{
*result.c11 = *c11 + *mat.c11;
*result.c12 = *c12 + *mat.c12;
*result.c21 = *c21 + *mat.c21;
*result.c22 = *c22 + *mat.c22;
}
else
{
// innermost matrix
result.data[0] = ...
}
return result;
}
};
This way, it costs less time-complexity and still looks simple to read. After it works, you can use single-block of matrix array inside of class to optimize for more speed, preferably only allocating once at root matrix and use
std::span
for access from submatrices for newer C++ versions. It is even parallelizable easily as each matrix can distribute its work to at least 4 threads and they can to 16 threads, 64 threads, etc. But of course too many threads are just as bad as too many allocations and should be optimized in a better way.
So I want to create a 4x4 matrix class which stores its data as a float** m.
I initialize it like this:
Matrix4f::Matrix4f()
{
this->m = new float*[4];
for (int i = 0; i < 4; i++)
{
this->m[i] = new float[4];
memset(this->m[i], 0, sizeof(float) * 4);
}
}
And after that, I have a destructor like this:
Matrix4f::~Matrix4f()
{
for (int i = 0; i < 4; i++)
{
delete[] m[i];
}
delete[] m;
}
But sometimes when I use this class, this line:
delete[] m[i];
Causes a breakpoint, and it throws: Critical error detected c0000374
Is this the right way of initializing and deleting a 4x4 matrix?
Edit: for future readers: my problem was that I didn't override the copy constructor of the matrix, and the assignment operator (void operator=(const Matrix&). This is a problem because it is possible that a copy is made silently (like saying Matrix4f mat = getTransformationMatrix();, and this matrix then gets deleted at the end of the scope, releasing the same pointer as the transformation matrix has, because the pointer is copied, not the contents. So override those two functions like in the accepted answers, and it will get rid of problems like this.
As pointed out in the comments, your code is fine, if and only if you corretly manage the case of copies.
You have three choices:
disable copy
shallow copy
deep copy
Let us discuss this choices:
you would need to only declare the copy constructor and the copy assigment operator delted. Now there is no way to copy objects of your class. This reduces the usefullness of the matrix-class.
This has no real value for its' own. Since you can achieve this by wrapping a object of type 3 into an std::shared_ptr.
There is no need for dynamic memory in this case. And even if there were, you would like to use a std::vector or something to manage the memory.
The sane solution would be to use an float[4][4] as m.
This would be more robust since you avoided the memory managment.
As already mentioned the rule of the three could be the issue. Your provided code is technical correct, however, if you copy a Matrix4f you have to reimplement the copy constructor and the overloaded assignment constructor:
#include <iostream>
class Matrix4f
{
public:
Matrix4f()
: m_data(new float*[4])
{
for (int i = 0; i < 4; i++)
m_data[i] = new float[4]{ 0 };
}
Matrix4f(const Matrix4f& source)
{
m_data = new float*[4];
for (int i = 0; i < 4; i++)
{
m_data[i] = new float[4]{ 0 };
for (int j = 0; j < 4; j++)
{
m_data[i][j] = source.m_data[i][j];
}
}
}
Matrix4f& operator=(const Matrix4f& source)
{
if (this == &source) return *this;
clear();
m_data = new float*[4];
for (int i = 0; i < 4; i++)
{
m_data[i] = new float[4]{ 0 };
for (int j = 0; j < 4; j++)
{
m_data[i][j] = source.m_data[i][j];
}
}
return *this;
}
~Matrix4f()
{
clear();
}
//private:
float**m_data;
void clear()
{
if (m_data != NULL)
{
for (int i = 0; i < 4; i++)
{
delete[] m_data[i];
}
delete[]m_data;
}
}
void print()const
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
std::cout << m_data[i][j] << "\t";
}
std::cout << "\n";
}
}
};
int main()
{
Matrix4f m1;
m1.m_data[0][0] = m1.m_data[1][1] = m1.m_data[2][2] = m1.m_data[3][3] = 1;
{
Matrix4f m2(m1);
Matrix4f m3 = m2;
m2.print();
m3.print();
}
m1.print();
}
But I recommend you to use one dimensional vectors instead, its much faster and much safer.
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).
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.
I am trying to pass a double* which holds an array of doubles, into the constructor of my class, and assign the value element for element.
Main:
int main()
{
double* data = new double[4];
data[0] = 1.1; data[1] = 2.2; data[2] = 3.3; data[3] = 4.4;
Matrix a(2,2,data);
return 0;
}
And this is my constructor:
Matrix::Matrix(int M, int N, double* input_data)
{
this->M = M;
this->N = N;
cout << "Matrix Constructor: M: " << M << "\tN: " << N << endl;
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
data[i*N+j] = input_data[i*N+j]; //***This is the problem***
}
}
}
Any attempt to index past input_data[0] in the constructor causes a crash. data[] can be accessed fine, and I can index past input_data[0] of data in my main function.
I'm assuming this should not be done this way, and would appreciate any nudge in the right direction.
It seems that you're not allocating memory for data in your constructor.
Matrix::Matrix(int M, int N, double* input_data)
{
data = new double[M*N];
//....
}
I assume that data is a member of Matrix class declared as double*.
You should allocate memory for this member in your constructor:
this->M = M;
this->N = N;
data = new double[M * N];
...
Don't forget to call delete[] data; in destructor. You should also call delete[] data; at the end of main.
You never allocated the memory to store the data.
Matrix::Matrix(int M, int N, double* input_data)
{
this->M = M;
this->N = N;
data = new double[N * M]; // Allocate space for N * M elements
cout << "Matrix Constructor: M: " << M << "\tN: " << N << endl;
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
data[i*N+j] = input_data[i*N+j]; //***This is the problem***
}
}
}
In C++, in order to allow for dynamic arrays like that you need to explicitly say that data is an array of size N * M. Otherwise, you're assigning into an undefined location which can be anywhere.
Did you allocate memory for data? Can't see that anywhere. However, I would not even bother with a constructor like that. Just take the dimensions as parameters (or as template parameters, but that's another thing I guess) and use a std::vector. Initialize the vector with N*M elements and overload the operator () for element access:
double& operator () (std::size_t i, std::size_t j);
const double& operator () (std::size_t i, std::size_t j) const;
As everyone pointed out, you didn't allocate space for data. Additionally, you'll need to provide a useful destructor, copy-constructor, and assignment operator.
All of this mishigas goes away if you use std::vector:
std::vector<double> data;
Matrix::Matrix(int M, int N, double* input_data)
: M(M), N(N), data(input_data, input_data+M*N)
{
// No work required in here
}