This question already has answers here:
Why Copy Constructor is called here instead of normal Constructor and overloaded assignment operator? [duplicate]
(3 answers)
Is there a difference between copy initialization and direct initialization?
(9 answers)
Closed 5 years ago.
I’m trying to do a simple exercise now with a Matrix and I want to implement this operations: Matrix a, Matrix b, Matrix c(a), Matrix d = a, Matrix e = a + b. For the moment I keep it simple but later I want to do the same thing, but with dynamic allocation and later with smart pointers.
I declared an explicit copy constructor and I overloaded operator=, I also declared a destructor so I have the rule of three.
Here are my functions:
Matrix& Matrix::operator=(const Matrix& opEven)
{
std::cout << "Operator = " << std::endl;
for (int i = 0; i < ORD; i++)
{
for (int j = 0; j < ORD; j++)
{
arr1[i][j] = opEven.arr1[i][j];
}
}
return *this;
}
Matrix::Matrix(const Matrix& obj)
{
std::cout << "Constructing matrix using copy c-tor." << std::endl;
for (int i = 0; i < ORD; i++)
{
for (int j = 0; j < ORD; j++)
{
arr1[i][j] = obj.arr1[i][j];
}
}
}
The problem is that, when I try to use Matrix d = a my compiler use the copy constructor, not my operator=.
Output:
When you call it like
Martix a;
Matrix b = a;
it always uses copy constructor. Try this:
Matrix a;
Matrix b:
b = a;
Basically, Matrix a = b; and Matrix a(b); is the same thing, because you are constructing matrix a using matrix b, so that causes a copy constructor call.
Related
This question already has an answer here:
Overloading operator-() in C++
(1 answer)
Closed 6 years ago.
Here is my code. The problem is i'm assigning array of class to zero in destructor and when I do operator overloading in my program the destructor is called and my arrays are automatically assigned with 0.
//Overloading Plus Operator
Array Array::operator +(Array &obj)
{
for (int i = 0; i < 10; i++)
{
this->arr[i] = this->arr[i] + obj.arr[i];
}
return *this;
}
//Overloading Minus Operator
Array Array::operator -(Array obj)
{
for (int i = 0; i < 10; i++)
{
this->arr[i] = this->arr[i] - obj.arr[i];
}
return *this;
}
//Overloading Assignment Operator
void Array::operator =(Array &obj)
{
for (int i = 0; i < 10; i++)
{
arr[i] = obj.arr[i];
}
}
//Class Destructor
Array::~Array()
{
cout << "\n\nDeleting Object " << this->objNum << "\n";
for (int i = 0; i < 10; i++)
{
arr[i] = 0;
}
cout << "\n\n";
}
When you get stuck like this, it's sometimes a big clue that you're doing something wrong.
And you are.
The function you are implementing is operator+, whose meaning is generally that x+y should leave x and y unchanged and produce a new object whose value is their sum....
However, your implementation is more like that of x += y: an operation that changes the value of x to be the sum of its original value and y.
The problems you are seeing is a symptom of that mismatch.
As an aside, your functions are also const-incorrect — to repair this, for example, declare operator+ as
Array operator +(const Array &obj) const
In fact, if you had additionally declared an operator[] that was const correct and accessed the contents of the internal array accessed the contents of the array using this operator, the compiler would have clued you into the fact that you shouldn't be modifying the contents of the array in operator+.
Im working on matrix template class, and now i should write the "=" operator overload.
What Im trying to do is to delete the matrix that appears in the left side of the '=', and return new one that equals to the matrix that appears in the right side of the '='.
because i can't delete "this" with a distructor, I delete it "manually" in the function. but now i should make a new matrix, therefor i make a new one ("temp") and return it.
The prblem is that "temp" is really return, but it doesn't set in the matrix that appears in the left side of the '='.
The code:
Matrix<int> m (3, 4);
Matrix<int> m2(2, 5);
m2 = m;
This was the main part.
The function:
template<class T>
Matrix<T> & Matrix<T>::operator=(Matrix<T>& mat)
{
if (this==&mat)
{
return *this;
}
for (int i = 0; i < this->rows; i++)
{
delete[] this->mat[i];
}
delete[] this->mat;
Matrix<T> * temp = new Matrix<T>(mat.rows, mat.cols);
for (int i = 0; i < temp->rows; i++)
for (int j = 0; j < temp->cols; j++)
{
temp->mat[i][j] = mat.mat[i][j];
}
return *temp;
}
template<class T>
Matrix<T>::Matrix(int row, int col)
{
rows = row;
cols = col;
mat = new T*[rows];
for (int i = 0; i < rows; i++)
{
mat[i] = new T[cols];
}
rester(*this);
}
Thx!!
Use std::vector as storage (instead of manal new and delete), and just accept the copy assignment operator generated by the compiler. It's that easy.
If you absolutely want to implement the copy assignment yourself, for learning, then just express copy assignment in terms of copy construction.
To do that, first define a noexcept swap operation:
// In class definition:
friend
void swap( Matrix& a, Matrix& b )
noexcept
{
using std::swap;
// swap all data members here
}
Then the copy assignment operator can be expressed as simply
// In class definition
auto operator=( Matrix other )
-> Matrix&
{
swap( *this, other );
return *this;
}
It's popular, an idiom, because it's very simple yet exception safe.
Instead of returning a reference, which adds verbosity and some possible marginal inefficiency for no gain, you might want to just use void as return type. However, probably for historical reasons, the containers in the standard library require the copy assignment operator to return a reference to self.
You need to allocate memory for this instead of creating a temp.
template<class T>
Matrix<T> & Matrix<T>::operator=(Matrix<T>& rhs)
{
if (this==&rhs)
{
return *this;
}
// Delete current memory
for (int i = 0; i < this->rows; i++)
{
delete[] this->mat[i];
}
delete[] this->mat;
this->rows = rhs.rows;
this->cols = rhs.cols;
// Allocate new memory
// Assign values to newly allocated memory.
this->mat = new int*[rhs.rows];
for (int = 0; i < rhs.rows; ++i )
{
this->mat[i] = new int[rhs.cols];
for (int j = 0; j < rhs.cols; j++)
{
this->mat[i][j] = rhs.mat[i][j];
}
}
// Return *this.
return *this;
}
I would recommend using the suggestion given in the answer by #Cheersandhth.
Also use a different name of the argument. Don't confuse with the member variable mat and the argument mat.
I am making a class to do matrix (and vector) math for a test I am running and to learn more C++. The class looks like this:
class utlMatrix
{
private:
int num_rows;
int num_cols; // number of columns
double **data; // array of pointers to the data
public:
// default constructor, with initialization
utlMatrix() : num_rows(0), num_cols(0), data(NULL) {};
// constructor with size
utlMatrix(int, int);
// destructor
~utlMatrix();
// copy constructor
utlMatrix(const utlMatrix&);
void copy(const utlMatrix &old); // copy 'old' to 'this'
void zero(); // sets all values to zero
void fill_rand(); //fills the data with random stuff
void print(std::ostream&); // prints the matrix to a file
// Operators
utlMatrix& operator=(const utlMatrix&); // copies matrices
friend utlMatrix operator+(const utlMatrix&, const utlMatrix&); // adds 2 matrices
utlMatrix operator*(const utlMatrix&) const;
//friend utlMatrix operator*(const utlMatrix&, const utlMatrix&); // multiplies 2 matrices
};
Copy Constructors, assignment operator and destructor
// copy constructor
utlMatrix::utlMatrix(const utlMatrix &old) {
copy(old);
}
utlMatrix& utlMatrix::operator=(const utlMatrix &old) {
copy(old);
return *this;
}
void utlMatrix::copy(const utlMatrix &old) {
num_rows = old.num_rows;
num_cols = old.num_cols;
data = new float*[num_rows];
for (int i = 0; i < num_cols; i++)
data[i] = new float[num_cols];
for (int i = 0; i < num_rows; i++)
{
for (int j = 0; j < num_cols; j++)
data[i][j] = old.data[i][j];
}
}
utlMatrix::~utlMatrix()
{
for (int i = 0; i < num_rows; i++)
delete [] data[i];
delete [] data;
}
Multiplication operators, I tried both, both failed if used twice in a row.
/*
utlMatrix operator*(const utlMatrix &left, const utlMatrix &right)
{
// first determine if the matrices can be multiplied
if (left.num_cols != right.num_rows)
{
std::cout << "Error using *, Inner dimensions must agree." << std::endl;
exit(-1);
}
// create the new matrix
utlMatrix newmat(left.num_rows, right.num_cols);
for (int i = 0; i < left.num_rows; i++)
for (int j = 0; j < right.num_cols; j++)
for (int k = 0; k < right.num_rows; k++)
newmat.data[i][j] += left.data[i][k] * right.data[k][j];
return newmat;
}
*/
utlMatrix utlMatrix::operator*(const utlMatrix &right) const
{
if ( this->num_cols != right.num_rows)
{
std::cout << "Error using *, Inner dimensions must agree." << std::endl;
return utlMatrix();
}
utlMatrix newmat(this->num_rows, right.num_cols);
for (int i = 0; i < this->num_rows; i++)
for (int j = 0; j < right.num_cols; j++)
for (int k = 0; k < right.num_rows; k++)
newmat.data[i][j] += this->data[i][k] * right.data[k][j];
return newmat;
}
The copy constructor, assignment and addition operators all work fine. When I try to multiply 1 matrix by another it works the first time but fails on the second. I altered the code to write out when it enter a constructor, operator and destructor in addition to printing the matrices after the multiplication. The math is good for the first matrix and the code fails with:
Unhandled exception at 0x776015de in sandbox.exe: 0xC0000005: Access violation writing location 0xcdcdcdcd.
From the screen output I know this is happening after the copy constructor is called following the second multiplication. The addition operator mirrors the first multiplication operator and appears to work fine, no exceptions, the copy constructor and destructor happen as expected. I found 2 answers on SO, Matrix class operator overloading,destructor problem and Matrix Multiplication with operator overloading. I checked to make sure that my pointers were not copied. The copy constructor does create a new object with a new pointer to data. If I run:
int main()
{
utlMatrix A(3,3);
utlMatrix B(2,2);
A.fill_rand();
B.fill_rand();
B = A;
return 0;
}
The debugger shows:
A {num_rows=3 num_cols=3 data=0x000365c0 ...} utlMatrix
B {num_rows=3 num_cols=3 data=0x00037c50 ...} utlMatrix
What did I miss? Here is how I actually used the operator. Failure occurs after D = A * B;
#include "utlMatrix.h"
int main()
{
// create the first matrices
utlMatrix A(3,3);
utlMatrix B(3,3);
utlMatrix C(3,2);
// fill them with random numbers
A.fill_rand();
B.fill_rand();
C.fill_rand();
utlMatrix D = A * B;
utlMatrix E = A * C;
utlMatrix F = B * C;
}
The error appeared to only show itself after the second or third call because that was when the matrices produced non-square output. These lines:
for (int i = 0; i < num_cols; i++)
data[i] = new float[num_cols];
in the copy constructor meant the non-square matrix was actually being built as a square matrix of size columns of the old one. Since my case was a matrix with more rows than columns it tried to put data into a non-existing memory location. Following the suggestions of Igor Tandetnik and Dave S, fixing the indexes and using SWAP fixed the problem.
I have narrowed down my issue to a derived classes copy constructor, but I am unsure of the cause.
EDIT: M, N and Data are Private. The error I recieve is 'Invalid allocation size: 4294967295 bytes' - which I understand is caused when passing a -1 to new. I'm unsure why this would occur unless the data is lost when the class comunicate.
BinaryMatrix::BinaryMatrix(const BinaryMatrix& copy) : Matrix(copy)
{
//cout << "Copy Constructor\n";
M = copy.M;
N = copy.N;
data = new double[M*N]; //This line causes the allocation error
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
data[i*N+j] = copy.data[i*N+j];
}
}
}
The above is my derived copy constructor which causes the error. I have marked the allocation line.
I can only assume that M and N are not being read correctly. Though I am unsure why. I'll include both derived and base constructors, and the base copy as well.
Thanks for any assistance.
MATRIX (BASE) CONSTRUCTOR
Matrix::Matrix(int M, int N, double* input_data)
{
this->M = M;
this->N = N;
//cout << "Matrix Constructor\n";
data = new double[M*N];
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
data[i*N+j] = input_data[i*N+j];
}
}
delete [] input_data;
}
MATRIX (BASE) COPY CONSTRUCTOR
Matrix::Matrix(const Matrix& copy)
{
//cout << "Copy Constructor\n";
M = copy.M;
N = copy.N;
data = new double[M*N];
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
data[i*N+j] = copy.data[i*N+j];
}
}
}
BINARYMATRIX (DERIVED) CONSTRUCTOR
BinaryMatrix::BinaryMatrix(int M, int N, double* input_data) : Matrix(M, N, input_data)
{
data = new double[M*N];
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
this->data[i*N+j] = this->getRead(i, j);
}
}
double thr_val = this->Mean();
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
if (this->data[i*N+j] > thr_val)
this->data[i*N+j] = 1;
if (this->data[i*N+j] < thr_val)
this->data[i*N+j] = 0;
}
}
}
Why do you create a new copy of the matrix data in the BinaryMatrix copy constructor? The copy constructor of Matrix you call from the BinaryMatrix copy constructor already does this.
In the BinaryMatrix copy constructor you discard the copy of the matrix data the Matrix copy constructor already made (without deleteing it) and create a new one. This is a memory leak - the memory will be exhausted if you do that often enough.
If M and N are private to Matrix and BinaryMatrix derives from Matrix, I am not sure why your code compiles (you should not be able to access M, N in BinaryMatrix). If your declaration of BinaryMatrix also includes members M and N (as well as Matrix::N and Matrix::M) then this could be the source of the problem.
If BinaryMatrix does not declare M and N, then I think we still don't have enough data to diagnose your problem. To guess a bit, perhaps M*N does not fit into the type used for M. So you have an arithmetic overflow. The array size is specified in size_t, so a cast will work OK.
Also, you probably want to delegate the management of the data to exactly one of the classes. That is, do either this:
BinaryMatrix::BinaryMatrix(const BinaryMatrix& copy) : Matrix(copy)
{
// M, N, data already set in Matrix::Matrix(const Matrix&)
// The data has also been copied, so there is nothing to do here.
}
or this:
#include <algorithm>
BinaryMatrix::BinaryMatrix(const BinaryMatrix& copy)
: Matrix(), M(0), N(0),
data(0) // null in case new throws an exception (avoid bad delete in dtor).
{
const size_t nelems(size_t(copy.M)*size_t(copy.N));
data = new double[nelems];
M = copy.M;
N = copy.N;
stl::copy(copy.data, copy.data+nelems, data);
}
I think generally it is not a good idea to use int for iterating over dynamic data structures, since nothing guarantees that the actual size of the structure fits into int. That guarantee does exist however for size_t (any existing object must have a size representable in size_t, so you can iterate over any contiguous object using size_t).
In fact, I'm not really sure what distinction (of purpose or behaviour) you're trying to get from Matrix and BinaryMatrix. The data seems to have the same representation. If it is a difference of behaviour but not representation you are looking for, I think it might be better to use composition (that is, a separate un-inherited representation class) rather than inheritance. See What is the Liskov Substitution Principle? for an explanation of how to think usefully about when to use inheritance.
However, if none of the answers you have seen so far actually helps to solve your problem, you should put some time into cutting down your example: what is the smallest complete example program which demonstrates your problem? Post that.
If the error is that M and N are private. then you must change there protection level to protected or public or provide an access method that is. Vairables defined in a base class that are private are innacceassable to the derived classes.
class A
{
int x;
}
class B : public A
{
int DoSomething()
{
return x; //This is an error X is private to class A and as such inaccessible.
}
}
I have a little bit of a problem... I understand what a EXC_BAD_ACCESS error is and I generally know how to fix it but this one has got me completely stuffed. I have this all within a class, here is one method:
double Matrix::get_element(int r, int c) const {
//Retrieve the element at row r and column c
//Should not modify the value stored in Matrix but return a double copy of the value
double currentValue = matrix[r][c];
return currentValue;
}
Now, I have another piece of my code that calls this method:
std::string Matrix::to_string() const {
std::string result;
double current;
Matrix working = *this;
std::ostringstream oss;
oss << "[";
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
current = 0.0;
current = working.get_element(i, j);
oss << " " << current << " ";
}
oss << "; ";
}
oss << "]";
result = oss.str();
return result;
}
I know that the working object has 3 rows and 3 cols at the point where working.get_element(i, j); is called. The variable list shows me just before the get_element() method, that both rows and cols are set to 3. In the method, I'm able to get the value at get_element(0, 0) but not get_element(0, 1).
I can't see why this is the case... Anyone know why or require more of my code to understand why these methods are being called?
EDIT:
Here is the header file:
class Matrix {
private:
//Any variables required
int rows;
int cols;
double **matrix;
public:
Matrix(); //Working M
~Matrix(); //Working M
Matrix(int r, int c); //Working M
int getRows();
int getCols();
void set_element(int r, int c, double val); //Working M
double get_element(int r, int c) const; //Working M
void clear(); //Working M
bool is_empty(); //Working M
bool is_identity(); //Working M
const Matrix transpose(); //Working M
int minorMat(double **dest, const int row, const int col, int order); //Working M
double get_determinent(); //Working M
double higherDeterminents(int order); //Working M
const Matrix operator+(const Matrix &rhs); //Working M
const Matrix operator-(const Matrix &rhs); //Working M
const Matrix operator*(const Matrix &rhs);
bool operator==(const Matrix &rhs); //NOT assessed
const Matrix operator*(const double &rhs);
const Matrix operator/(const double &rhs);
Matrix & operator=(const Matrix &rhs);
std::string to_string() const;
};
Do ignore the comments sorry. And this is the constructors/destructors:
Matrix::Matrix() {
//Basic Constructor
rows = 1;
cols = 1;
matrix = new double*[rows];
for (int i = 0; i < rows; ++i) {
matrix[i] = new double[cols];
}
}
Matrix::~Matrix() {
//Basic Deconstructor
for (int i = 0; i < rows; ++i) {
delete[] matrix[i];
}
delete[] matrix;
rows = NULL;
cols = NULL;
matrix = NULL;
}
Matrix::Matrix(int r, int c) {
//Empty matrix (all 0's) with r rows and c columns, if they are -ve, set to 1
rows = r;
cols = c;
if (cols < 0)
cols = 1;
if (rows < 0)
rows = 1;
matrix = NULL;
matrix = new double*[rows];
for (int i = 0; i < rows; i++) {
matrix[i] = new double[cols];
}
}
EDIT2:
Matrix & Matrix::operator=(const Matrix &rhs) {
//rhs is matrix to be copied
//rhs compied into Matrix called on
double toCopy;
for (int i = 0; i < rhs.rows; i++) {
for (int j = 0; j < rhs.cols; j++) {
toCopy = rhs.get_element(i, j);
this->set_element(i, j, toCopy);
}
}
return *this;
}
It is impossible for us to say when you do not state how you declare and initialize the matrix element. Using something like that in your CTOR should be fine:
class Matrix {
float matrix[3][3];
...
}
Don't forget to initialize it in your CTOR to something that makes sense.
Btw: why do you do this: Matrix working = *this; ?? You could simply this->get_element(i, j); instead, which would not invoke copying of your whole object. [1]
EDIT: Update since you updated your answer. You should be careful with your copy CTORs and operator=() statements. It is easily possible to make double deletes or something ugly like that.
EDIT2: I think the problem is this line:
Matrix working = *this;
You are creating a new copy working of your this object. But working gets initialized with only 1 column and 1 row (as defined in your standard CTOR). I'm not sure if you are checking the bounds when calling set_element or get_element so I guess you are writing over the bounds of your arrays.
I think the best idea is to just remove the line Matrix working = *this; and to adhere to my tip in above:
this->get_element(i, j); in std::string Matrix::to_string() const.
Your Matrix(int r, int c) allocates memory for matrix, but leaves the values it points to uninitialized. Add something like this to the constructor:
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
this->set_element(i, j, 0);
}
}
Doing like this:
int main()
{
Matrix m(3,3);
std::cout << m.to_string();
}
Output:
[ 0 0 0; 0 0 0; 0 0 0; ].
Same thing in the default constructor:
Matrix::Matrix() {
//Basic Constructor
rows = 1;
cols = 1;
matrix = new double*[rows];
for (int i = 0; i < rows; ++i) {
matrix[i] = new double[cols];
}
}
You allocated memory, but wherever matrix[0][0] points to, it's uninitialized garbage value. Do something like matrix[0][0] = 0; or whatever default value you want it to have.
Hope that helps.
Your class is violating the "big three" rule. If a class has one of a destructor, assignment operator or copy constructor then it most probably you need to have all three.
In your case you have a destructor, but no assignment operator or copy constructor, and this is going to create an UB condition when you do Matrix working = *this.
By the way there are two other problems with your code
From the comment seems that you think that new double[size] will initialize the elements to 0 and this is not true.
Most of your code is technically very bad. Your matrix class would be much easier (less code) to implement correctly using std::vector instead of pointers and dynamic memory. Of course if this is just an exercise then it make sense to avoid using std::vector.
By the way if you never heard about the "big three" rule chances are that you're trying to learn C++ with experimentation instead that by reading.
With C++ this is not a smart move... logic can be used as substitute for study if 1) the topic is highly logical, 2) if you can be told when you get it wrong.
Instead C++ is very very complex and in a few place is also quite illogical (for historical reasons) so there are parts in which logic will simply misguide you.
Moreover when you make a mistake in C++ you don't get in general an error message, but "Undefined Behavior". This basically makes very very hard to learn C++ with experimentation because even wrong code may apparently work. It is also very easy to write code that looks good and that is instead quite wrong for subtle reasons.
Instead of just experimenting you should grab a good book and read it cover to cover...