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
}
Related
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...
For the following mymatrix class definition, why don't I need the commented parts of the destructor? Don't we need to delete what the a pointer points to as well? Or is it because we deleted all the meaningful data that we don't need these (commented-out) parts of the destructor?
template<typename T>
class mymatrix
{
private:
struct ROW
{
T* Cols; // dynamic array of column elements
int NumCols; // total # of columns (0..NumCols-1)
};
ROW* Rows; // dynamic array of ROWs
int NumRows; // total # of rows (0..NumRows-1)
}
Destructor:
virtual ~mymatrix()
{
for(int r=0;r<numRows;r++)
{
for(int c=0;c<Rows[r].NumCols;c++)
{
delete Rows[r].Cols[c];
}
// delete Rows[r];
}
// delete Rows;
}
Constructor:
mymatrix(int R, int C)
{
if (R < 1)
throw invalid_argument("mymatrix::constructor: # of rows");
if (C < 1)
throw invalid_argument("mymatrix::constructor: # of cols");
Rows = new ROW[R]; // an array with R ROW structs:
NumRows = R;
//intialize each row to C columns
for(int r=0;r<R;r++){
Rows[r].Cols=new T[C];
Rows[r].NumCols=C;
//initialize elements to their default value
for(int c=0;c<Rows[r].NumCols;c++){
Rows[r].Cols[c]=T{}; // default value for type T;
}
}
}
You need to use array-delete syntax because you are deleting arrays, not single objects:
delete[] Rows[r].Cols
...
delete[] Rows
Edit: I originally simply included the correct delete[] operator usage and left everything unchanged in my original example for brevity, but as #idclev463035818 pointed out, whenever you define your own destructor, copy constructor, or copy assignment operator (especially when they involve dynamic memory allocation), you almost always need to have all three. Almost never do you want any one without the others because if you have raw pointers in your object, then they will be shallow-copied to the new objects being instantiated. Then later on, the destructors for each of these objects will be called and attempt to delete the same portions of memory multiple times, which is a major error. I've added these to the code example and make use of them in new tests in the main function.
Full code:
#include <iostream>
using namespace std;
template<typename T>
class mymatrix
{
public:
struct ROW
{
T* Cols; // dynamic array of column elements
int NumCols; // total # of columns (0..NumCols-1)
};
ROW* Rows; // dynamic array of ROWs
int NumRows; // total # of rows (0..NumRows-1)
public:
mymatrix(int R, int C)
{
init(R, C);
}
void init(int R, int C) {
if (R < 1)
throw "";//throw invalid_argument("mymatrix::constructor: # of rows");
if (C < 1)
throw "";//invalid_argument("mymatrix::constructor: # of cols");
Rows = new ROW[R]; // an array with R ROW structs:
NumRows = R;
//intialize each row to C columns
for (int r = 0; r < R; r++) {
Rows[r].Cols = new T[C];
Rows[r].NumCols = C;
//initialize elements to their default value
for (int c = 0; c < Rows[r].NumCols; c++) {
Rows[r].Cols[c] = T{}; // default value for type T;
}
}
}
mymatrix(const mymatrix& other) : mymatrix(other.NumRows, other.Rows[0].NumCols) {
for (int r = 0; r < NumRows; ++r) {
ROW& thisRow = Rows[r];
ROW& otherRow = other.Rows[r];
for (int c = 0; c < thisRow.NumCols; ++c) {
thisRow.Cols[c] = otherRow.Cols[c];
}
}
}
mymatrix& operator=(const mymatrix& other) {
if (other.NumRows != NumRows || other.Rows[0].NumCols != Rows[0].NumCols) {
clear();
init(other.NumRows, other.Rows[0].NumCols);
}
for (int r = 0; r < NumRows; ++r) {
ROW& thisRow = Rows[r];
ROW& otherRow = other.Rows[r];
for (int c = 0; c < thisRow.NumCols; ++c) {
thisRow.Cols[c] = otherRow.Cols[c];
}
}
return *this;
}
void clear() {
for (int r = 0; r < NumRows; r++)
{
delete[] Rows[r].Cols;
}
delete[] Rows;
Rows = NULL;
NumRows = 0;
}
virtual ~mymatrix()
{
clear();
}
};
int main() {
mymatrix<int> mat(5, 5);
mat.Rows[0].Cols[2] = 5;
mymatrix<int> matClone(mat);
cout << matClone.Rows[0].Cols[2] << endl;
matClone.Rows[0].Cols[1] = 8;
cout << mat.Rows[0].Cols[1] << endl;
mat = matClone;
cout << mat.Rows[0].Cols[1] << endl;
system("pause");
return 0;
}
I'm telling this every time I see the usage of new/delete in C++.
Please don't use new/delete in C++!
Here is a minimal example of how to create a matrix which will allocate and delete itself without any manual memory allocations.
#include <vector>
class Matrix : public std::vector<std::vector<int>> {
public:
Matrix(size_t numRows, size_t numCols)
: std::vector<std::vector<int>>(numRows, std::vector<int>(numCols, 0)) {}
size_t numRows() const { return size(); }
size_t numCols() const { return front().size(); }
};
int main() {
auto m = Matrix(5, 4);
return m[4][3];
}
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'm just going to preface this with the fact that I'm new to C++ so it's quite possible there's just a stupid error here, but I can't find it.
I'm just trying to overload the increment operator in a friend function. Everything compiles perfectly and everything works if I explicitly call the postfix increment overload:
operator++(*test, 0);
Every element in the matrix is incremented and the program prints it out using cout perfectly. The problem is when I try to do the normal ++ increment test++; it appears as though something wrong happens with the test pointer to where when it tries to print the test object it doesn't print anything.
Any idea what's going on? I'm clueless. Here's the code I'm working with...
Compile & Run
g++ -o App App.cpp Matrix.cpp
./App
App.cpp
#include <iostream>
#include "Matrix.h"
using namespace std;
#define X 9
int main(int argc, char *argv[])
{
// Start the actual program here
Matrix* test = new Matrix(3,3);
// Row 1
test->setElement(0,0,1);
test->setElement(0,1,2);
test->setElement(0,2,3);
// Row 2
test->setElement(1,0,4);
test->setElement(1,1,5);
test->setElement(1,2,6);
// Row 3
test->setElement(2,0,7);
test->setElement(2,1,8);
test->setElement(2,2,9);
operator++(*test, 0);
//test++;
//++test;
// Print the Matrix object
cout << *test << endl;
}
Matrix.h
#ifndef MATRIX_H
#define MATRIX_H
#include <iostream>
using namespace std;
class Matrix {
friend ostream& operator<<(ostream&, const Matrix&);
friend Matrix& operator++(Matrix&); // prefix increment
friend Matrix& operator++(Matrix&, int); // postfix increment
private:
int rows;
int cols;
int** elements;
public:
// Constructors
Matrix(int);
Matrix(int,int);
Matrix(const Matrix&);
// Define setters
void setElement(int,int,int);
// Define getters
int getRowCount();
int getColCount();
int getElementAt(int,int);
void increment();
// Destructor
~Matrix();
};
#endif
Matrix.cpp
#include <iostream>
#include "Matrix.h"
using namespace std;
//===================================
// DEFINE [CON]/[DE]STRUCTORS
//===================================
// Constructor for creating square matricies
Matrix::Matrix(int _size) {
rows = _size;
cols = _size;
elements = new int*[_size];
for (int i = 0; i < _size; i++) {
elements[i] = new int[_size];
}
}
// Constructor for supporting non-square matricies
Matrix::Matrix(int _rows, int _cols) {
rows = _rows;
cols = _cols;
elements = new int*[_rows];
for (int i = 0; i < _rows; i++) {
elements[i] = new int[_cols];
}
}
// Copy constructor
Matrix::Matrix(const Matrix& mat1) {
Matrix(mat1.rows, mat1.cols);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
elements[i][j] = mat1.elements[i][j];
}
}
}
// Destructor
Matrix::~Matrix() {
for (int i = 0; i < rows; i++) {
delete[] elements[i];
}
delete[] elements;
}
//===================================
// DEFINE SETTER FUNCTIONS
//===================================
void Matrix::setElement(int row, int col, int newElement) {
if (row > rows-1 || row < 0)
throw "Row out of index";
if (col > cols-1 || col < 0)
throw "Column out of index";
elements[row][col] = newElement;
}
//===================================
// DEFINE GETTER FUNCTIONS
//===================================
int Matrix::getRowCount() { return rows; }
int Matrix::getColCount() { return cols; }
int Matrix::getElementAt(int row, int col) {
if (row > rows-1 || row < 0)
throw "Row out of index";
if (col > cols-1 || col < 0)
throw "Column out of index";
return elements[row][col];
}
//===================================
// OVERRIDE OPERATOR FUNCTIONS
//===================================
// Print the Matrix to the output stream
ostream& operator<<(ostream& out, const Matrix& mat) {
for (int i = 0; i < mat.rows; i++) {
for (int j = 0; j < mat.cols; j++) {
out << mat.elements[i][j] << " ";
}
out << endl;
}
return out;
}
// Prefix. Increment immediately and return the object.
Matrix& operator++(Matrix& mat) {
cout << "Prefix ++ operator" << endl;
// Increment all elements in the object by 1
for (int i = 0; i < mat.rows; i++) {
for (int j = 0; j < mat.cols; j++) {
mat.elements[i][j] += 1;
}
}
return mat;
}
// Postfix. Return the current object and "save" the incremented.
Matrix& operator++(Matrix& mat, int x) {
cout << "Postfix ++ operator" << endl;
// Save the current values
Matrix* curVals = new Matrix(mat);
// Increment the object
++(mat);
// Return the unincremented values
return *curVals;
}
test++ increments the value of test, so that it will point to the memory after your Matrix object. You need to dereference the pointer to get a Matrix object, then apply the increment to that.
What you want is (*test)++ or ++*test.
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).