I'm having trouble multiplying objects using the overloaded * operator
In the class I have the operator defined as:
const Matrix operator*(Matrix& B);
The implementation is
const Matrix Matrix::operator* (Matrix& B){
Matrix r = Matrix(B.M,B.N);
for(int i = 0; i < r.M; i++){
for(int j = 0; j < r.N; j++){
r.data[i*N+j] = (*this)(i,j) * (int)B(i,j);
}
}
return r;
}
When I call
Matrix C = A * B
I will get the expected result, however calling
C = C * C
Results in an error.
I'm guessing it's to with the calling object C but I'm not sure what to do!
EDIT:
My assignment operator. Matrix R is a deep copy.
Matrix Matrix::operator=(Matrix& B){
Matrix r(M,N);
for(int i = 0; i < M; i++){
for(int j = 0; j < N; j++){
r.data[i*N+j] = B(i,j);
}
}
return r;
}
The error is because you are storing your data in a variable called "data" (which is an int[] on the heap) and you haven't overridden your assignment operator to copy the values from the object being copied into the current member variable "data". So, the default assignment operator will copy the "data" pointer for you, which in your case is from a temporary value that will be out of scope after the assignment. Your destructor will most likely delete the "data" variable you are now pointing to because the temporary goes out of scope.
You have defined your own copy constructor to establish the "data" variable on the heap. The first example you have where Matrix C = A * B will use that copy constructor, which works.
The second example uses the default assignment operator, which will only copy the data pointer from the temporary value returned from the operation. Thus, you basically have no value that data is pointing to.
You have to define an assignment operator to make this work.
Here are suggested functions to go along with your copy constructor:
void Matrix::swap(Matrix& other)
{
std::swap(M, other.M);
std::swap(N, other.N);
std::swap(data, other.data);
}
Matrix& Matrix::operator= (Matrix matrix)
{
swap(matrix);
return *this;
}
Matrix Matrix::operator* (const Matrix& B)
{
Matrix r = Matrix(B.M,B.N);
for(int i = 0; i < r.M; i++){
for(int j = 0; j < r.N; j++){
r.data[i*N+j] = (*this)(i,j) * (int)B(i,j);
}
}
return r;
}
This works well because the copy constructor will be used for "matrix" in assignment operator (operator=). Then, the swap function will trade the "data" array with the temporary copy of Matrix. Therefore, you will copy the appropriate "data" from the operation*'s temporary variable.
This has nothing to do with "calling object C".
The first version
Matrix C = A * B;
uses constructor(s) or class Matrix to initialize new object C.
The second version
C = C * C;
uses assignment operator of class Matrix to assign new value to an existing object C.
You managed to screw up the assignment operator declaration/implementation somehow (which you don't show in the code you posted), which is why the second version does not compile.
There are problems with your operator * declaration as well. Even if you want to have it as class member, a more meaningful way to declare it would be
Matrix Matrix::operator* (const Matrix& B) const {
...
Note how const qualifiers are placed.
EDIT: So, here's your problem. Your assignment operator is completely broken.
Firstly, you declared your assignment operator as
Matrix Matrix::operator=(Matrix& B)
This operator cannot accept temporary objects on the right-hand side because you failed to declare the parameter as const. Non-const references cannot be bound to temporary objects. And in C = C * C the right-hand side of assignment is actually a temporary object produced by *operator.
Redeclare your assignment operator as
Matrix &Matrix::operator=(const Matrix& B)
Note, it accepts a const reference and returns a reference.
Secondly, your assignment operator is supposed to assign to *this, not to some standalone temporary object. And it is supposed to return a reference to *this. In other words, the implementation should be something along the lines of
Matrix &Matrix::operator=(const Matrix& B){
// Resize `*this` to match the size of `B`
for(int i = 0; i < M; i++){
for(int j = 0; j < N; j++){
this->data[i*N+j] = B(i,j);
}
}
return r;
}
Try to define the operator like this:
Matrix operator* (const Matrix& x, const Matrix& y)
{
//...
}
Related
I realize that there are examples after examples of overloading the assignment operator on the web, but I have spent the last few hours trying to implement them in my program and figure out how they work and I just can't seem to do it and any help would be greatly appreciated.
I am trying to implement an overloaded assignment operator function.
I have 3 files working, the Complex.h header file, a Complex.cpp definition file, and a .cpp file I'm using as a driver to test my Complex class.
In the Complex.h header file my prototype for the assignment operator:
Complex &operator= (Complex&);
And so far what I have for the definition of the overloaded operator in my .cpp file is:
Complex &Complex::operator=(Complex& first)
{
if (real == first.real && imaginary == first.imaginary)
return Complex(real, imaginary);
return first;
};
And the way I'm calling my assignment operator in my functions is:
x = y - z;
So specifically, my problem is that when I call the overloaded assignment operator with x = y -z, it doesn't assign the passed in value to x when I return the passed in value and I'm unable to figure out why from numerous examples and explanations on the web, any help would be greatly appreciated and I thank you for any help ahead of time.
I think you need the following operator definition
Complex & Complex::operator =( const Complex &first )
{
real = first.real;
imaginary = first.imaginary;
return *this;
};
You have to return reference to the object that is assigned to. Also the parameter should be a constant reference. In this case you may bind the reference to a temporary object or you have to write also a move assignment operator.
In your implementation of the copy assignment operator you do not change the assigned object.:) You simply create a temporary and return reference to this temporary or return reference to first.
Assignment takes in two objects, the object to be assigned to, and the object with the desired value.
Assignment should:
modify an existing object, the object being assigned to
Assignment should not:
create a new object
modify the object that has the desired value.
So let's say the object type we're dealing with is:
struct S {
int i;
float f;
};
A function that performs assignment might have the signature:
void assignment(S &left_hand_side, S const &right_hand_side);
And it would be used:
S a = {10, 32.0f};
S b;
assignment(b, a);
Notice:
the left hand side object is modifiable, and assignment will modify it, rather than create a new object.
the right hand side object, the object with the desired value, is not modifiable.
Additionally, in C++ the built-in assignment operation is an expression rather than a statement; it has a value and can be used as a subexpression:
int j, k = 10;
printf("%d", (j = k));
This sets j equal to k, and then takes the result of that assignment and prints it out. The important thing to note is that the result of the assignment expression is the object that was assigned to. No new object is created. In the above code, the value of j is printed (which is 10, because j was just assigned the value 10 from k).
Updating our earlier assignment function to follow this convention results in a signature like:
S &assignment(S &left_hand_side, S const &right_hand_side);
An implementation looks like:
S &assignment(S &left_hand_side, S const &right_hand_side) {
// for each member of S, assign the value of that member in
// right_hand_side to that member in left_hand_side.
left_hand_side.i = right_hand_side.i;
left_hand_side.f = right_hand_side.f;
// assignment returns the object that has been modified
return left_hand_side;
}
Note that this assignment function is not recursive; it does not use itself in the assignment, but it does use assignment of the member types.
The final piece of the puzzle is getting the syntax a = b to work, instead of assignment(a, b). In order to do this, all you have to do is make assignment () a member function:
struct S {
int i;
float f;
S &assignment(S &left_hand_side, S const &right_hand_side) {
left_hand_side.i = right_hand_side.i;
left_hand_side.f = right_hand_side.f;
return left_hand_side
}
};
Replace the left_hand_side argument with *this:
struct S {
int i;
float f;
S &assignment(S const &right_hand_side) {
this->i = right_hand_side.i;
this->f = right_hand_side.f;
return *this;
}
};
And rename the function to operator=:
struct S {
int i;
float f;
S &operator=(S const &right_hand_side) {
this->i = right_hand_side.i;
this->f = right_hand_side.f;
return *this;
}
};
int main() {
S a, b = {10, 32.f};
S &tmp = (a = b);
assert(a.i == 10);
assert(a.f == 32.f);
assert(&tmp == &a);
}
Another important thing to know is that the = sign is used in one place that is not assignment:
S a;
S b = a; // this is not assignment.
This is 'copy initialization'. It does not use operator=. It is not assignment. Try not to confuse the two.
Points to remember:
assignment modifies the object being assigned to
assignment does not modify the object being assigned from.
assignment does not create a new object.
assignment is not recursive, except insofar as assignment of a compound object makes use of assignment on all the little member objects it contains.
assignment returns the object after modifying its value
copy initialization looks sort of like assignment, but has little to do with assignment.
An overloaded assignment operator should look like this:
Complex &Complex::operator=(const Complex& rhs)
{
real = rhs.real;
imaginary = rhs.imaginary;
return *this;
};
You should also note, that if you overload the assignment operator you should overload the copy constructor for Complex in the same manner:
Complex::Complex(const Complex& rhs)
{
real = rhs.real;
imaginary = rhs.imaginary;
};
In my main, I am calling a function (func1)in a loop. This function is a member of Class1. I am passing an object (object2) of a different class, Class2 to this function. On the first iteration of the loop, the variable var2 (member of Class2) is accessible from main, but on the second iteration, it is not. I get an "Access violation reading location" error. Here is what my code looks like:
main.cpp:
#include "Class1.h"
int main(){
Class2 object2;
object2.assign_var2();
Class1 object1;
for (int i = 0; i < 2; ++i){
std::cout << object2.var[0][0][0] << std::endl; // Works ONLY on first iteration
object1.func1(object2)
}
}
Class2.h:
class Class2{
... other variables and functions declared
public:
Class2::Class2();
Class2::~Class2();
double *** var2;
void assign_var2();
}
Class2.cpp:
Class2::Class2(){
var2 = new double**[200];
for (int i = 0; i < 200; ++i) {
var2[i] = new double*[200];
for (int j = 0; j < 200; ++j){
var2[i][j] = new double[2];
}
}
Class2::~Class2(){
for (int i = 0; i < 200; ++i){
for (int j = 0; j < 200; ++j){
delete [] var2[i][j];
}
delete [] var2[i];
}
delete [] var2;
}
void assign_var2(){
for (int i = 0; i<200; ++i){
for (int j = 0; j<200; ++j){
var2[i][j][0] = some_number1;
var2[i][j][1] = some_number2;
}
}
}
}
Class1.h:
#include "Class2.h"
class Class1{
... other variables, functions declared
public:
void func1(Class2)
}
Class1.cpp:
Class1::func1(Class2 object2){
int u = object2.var2[1][2][0];
int v = object2.var2[1][2][1];
}
Side note: If I try and print a different variable instead of var2, it seems to work on the second iteration, so I don't think it's a problem with the object itself.
Thanks in advance!!
The problem is that Class1::func1(Class2 object2) accepts the argument by value. This means that a copy of the Class2 object is being made, and then destructed when func1() returns.
In the Class2 class you do not define a copy constructor, so the compiler is creating one for you that simply copies the members by-value. Then when the copy's destructor runs, it deletes all of the allocations, leaving the original object with a pointer to an invalid object. This is why it fails on the second iteration.
Always follow the rule of three: if you need a custom destructor, copy constructor, or copy assignment operator, you need all three of them. A proper copy constructor will create new allocations for all of the arrays and copy the data to them. (If you are using C++11 then it's actually the rule of five: you probably also want to implement a move constructor and move assignment operator so that you can "steal" the var2 pointer in cases where you know that the object being assigned is an rvalue and therefore will be going away soon anyway.)
In your case, the fix is simple: accept the argument by value:
Class1::func1(Class2 const & object2)
I would strongly suggest using std::vector<std::vector<std::vector<double>>> for your var2 member instead, because then the compiler-generated destructor, copy-constructor, and copy-assignment operator will all do the right thing, and you won't need to implement any of them.
This works hand-in-hand with making func1() accept a reference: while the error is happening because there isn't a custom copy constructor, we really don't even want to make a copy here because we're not modifying the data. Copying the data only to destroy the copy is silly; let's just accept a reference to an existing object instead of requiring a superfluous copy.
Alternatively, you can just disable copying altogether:
class Class2 {
// ...
// For C++11: explicitly delete the copy-ctor and copy-assignment operator.
public:
Class2(Class2 const &) = delete;
Class2 & operator=(Class2 const &) = delete;
// For C++03: declare the copy-ctor and copy-assignment operator private and
// then do not implement them. (C++03 doesn't have the "= delete" syntax.)
private:
Class2(Class2 const &);
Class2 & operator=(Class2 const &);
If you disable copying then you would get a compile-time error on the call object1.func1(object2) because it depends on the existence of a copy-constructor for object2.
Have problem with copy constructor and assignment operator. Have written code to multiply matricies:
Matrix& Matrix::operator * (const Matrix &second) const
{
// Create result matrix
Matrix result(Rows(), second.Columns());
// Multiply matricies
for (unsigned i = 0; i < Rows(); i++)
{
for (unsigned j = 0; j < second.Columns(); j++)
{
result[i][j] = 0.0;
for (unsigned k = 0; k < Columns(); k++)
{
result[i][j] += m_matrix[i][k] * second[k][j];
}
}
}
return result;
}
In Main code I call the operator:
Matrix C = A * B;
However code destroys result variable before assignment, how to write such code correctly to return result matrix? Copy constructor is:
Matrix::Matrix(const Matrix& matrix)
{
AllocateMatrixArray(matrix.Rows(), matrix.Columns());
CopyMatrixData(matrix);
}
Assignment operator is:
Matrix& Matrix::operator = (const Matrix& other)
{
AllocateMatrixArray(other.Rows(), other.Columns());
CopyMatrixData(other);
return *this;
}
However I see that compiler does not use it - copy constructor is enough.
Your code returns a reference to a local variable, which will be destroyed at the end of the function's scope. Don't do that:
Matrix Matrix::operator * (const Matrix &second) const {
// same as above
}
Note that the return value is now a Matrix instead of a Matrix&.
You should not be returning a reference to local variable. By convention the opertor*(I mean the two argument version of course) returns a copy to the result. Same holds true for the other operations like operator+, operator- and so on. A reference is returned by the moifying versions of those operators like operator *=, operator += and so on.
If you want to write expressions like C = A*B all C A and B must be "values".
So the return value of operator* must be matrix and not matrix&, espscialy if the & refers to a local variable (like result) thet will be destroyed at } (hence before = is executed).
That said, there are some more issues:
The sample Matrix C = A*B is not an assignment: an assignment happens the the value of an already existent object is changed. But Matrix C is created contextually: in fact, what it is called here, is the Matrix constructor (copy constructor, in this case)
There could be memory leaks: Although I don't see how the matrices data are handled, your operator=
seems to allocate new space and then copy the data in it. But what happens to the space containing the old data? Does it remain forgotten around? Is is automatically released by a smart pointer?
Similarly, just like = should dismiss the old data, also the class itself should dismiss its own data on destruction, hence a destructor should also be implemented. Otherwise every time a Matrix is dismissed (like the local result), its data will stay around.
I have a custom-made Matrix library for a neural network program and overloaded arithmetic operators.
Here's the class declarations:
class Matrix{
public:
int m;
int n;
double **mat;
Matrix(int,int);
Matrix(int);
Matrix(const Matrix& that):mat(that.mat),m(that.m),n(that.n)
{
mat = new double*[m];
for(int i = 0;i<m;i++)mat[i] = new double[n];
};
~Matrix();
friend istream& operator>>(istream &in, Matrix &c);
friend ostream& operator<<(ostream &out, Matrix &c);
Matrix operator+(const Matrix& other);
};
This is the function definition for + operation:
Matrix Matrix::operator+(const Matrix& other)
{
Matrix c(m,n);
for(int i=0;i<m;i++)
{
for(int j = 0; j<n;j++)
c.mat[i][j] = mat[i][j] + other.mat[i][j];
}
return c;
}
I have tried to implement it in all ways and error is same...here's an instance
Matrix x(m,n); //m and n are known
x = a+b; // a and b are also m by n matrices
I have debugged the code using breakpoints and here's the error...
The local matrix 'c' in operator function is destroyed before it is returned and hence what is assigned to x is a garbage pointer..
Please suggest me something...
You need to define a copy constructor for your class. The copy constructor will need to allocate memory for mat and make a copy of the data.
Without this, when you return c, a new object is constructed that has the same value of mat as c. When c subsequently goes out of scope, it deletes c.mat. As a result, the copy of c is left with a dangling pointer.
Having done this, you should also implement an assignment operator.
The value you returned is used to initialize a temporary, and this temporary is then copied into the result after the value you returned has been destroyed. This is normal behavior (unless the call is elided because of NRVO).
However, since your class has no explicitly defined copy constructor, the implicitly generated one will be invoked, and that will just copy a pointer (mat) to stuff that has been deallocated by the returned object's destructor.
This is a violation of the so-called Rule of Three, a programming best-practice saying that whenever your class explicitly defines a copy-constructor, an assignment operator, or a destructor, then it should define all of them. The rationale is that a class that defines one of them most likely does so because it is managing some resource, and for correctly handling resource releasing/acquiring logic, all of those three special member functions are needed.
Notice that in C++11 you can also have a move constructor that will be allowed to perform the transfer of the Matrix's content just by assigning pointers and invalidating the object you moved from.
Matrix(Matrix&& m)
{
mat = m.mat;
m.mat = nullptr;
}
Of course, if you introduce a move constructor, you will have to modify your class destructor accordingly to check if you really have to release the allocated memory:
~Matrix()
{
if (m.mat == nullptr)
{
return;
}
...
}
Your Matrix class has a raw pointer member and presumably allocates memory in its constructors, yet you have no copy constructor or copy assignment operator.
Also, you have a destructor, yet you have no copy constructor or copy assignment operator. This is a violation of the Rule of Three.
Your Matrix c is a local variable. So it is destroyed when that method where it was created ends. In C++ this unwanted situation is usually solved by copying objects. You can define copy constructor and assignment operator = with the same functionality. The problem of copying is that it is slow, so if you want it to be faster, you should use a different approach withotu copying. For example, you can add a parameter to the method where caller would pass a reference to the existing matrix object where to store the result.
You need a copy constructor and an assignment operator for your class that make a deep copy of the object as the compiler generated functions will not.
The compiler generated copy constructors and assignment operators will simply copy the objects contained in the class. In your case these are PODs, so the automatically generated functions will simply do a bitwise copy. In the case of the double**, this will result in the copy of the pointer value, not the pointed to values. As a result, you end up with two Matrix objects pointing to the same underlying data, just before the destructor pulls the rug out from underneath you.
You should change your code to return a Matrix *, rather than a Matrix object. This way you can ensure that the Matrix object lives after the function. (Your current code makes the Matrix object a function variable, thus it will be removed after the function has ended).
Your code could look like this:
Matrix *Matrix::operator+(const Matrix& other)
{
Matrix *c = new Matrix(m,n);
for(int i=0;i<m;i++)
{
for(int j = 0; j<n;j++)
c->mat[i][j] = mat[i][j] + other.mat[i][j];
}
return c;
}
EDIT: Apparently this is bad practice, guess I also learned something today :)
I was trying to write a matrix class which would be able to find inverse,adjoint,etc. of a square matrix of any order.
The constructor initializes an identity matrix of order n(passed to it).
class Matrix
{
int** elements;
int order;
public:
Matrix& operator=(const Matrix& second_inp)
{
if(this->order!=second_inp.order)
cout<<"The matrix cannot be assigned!!!\n"<<this->order<<"\n"<<second_inp.order;
else
{
for(int i=0;i<this->order;i++)
for(int j=0;j<this->order;j++)
this->elements[i][j] = second_inp.elements[i][j];
}
return *this;
}
Matrix operator*(const Matrix& a)const
{
Matrix c(a.order);
for(int i=0;i<c.order;i++)
for(int j=0;j<c.order;j++)
c.elements[i][j]=0;
if (this->order!=a.order)
{
cout<<"The 2 Matrices cannot be multiplied!!!\n";
return Matrix();
}
else
{
for(int i=0;i<a.order;i++)
for(int j=0;j<a.order;j++)
for(int k=0;k<a.order;k++)
c.elements[i][j] += (this->elements[i][k])*(a.elements[k][j]);
return c;
}
}
};
~Matrix()
{
for(int i=0;i<this->order;i++)
delete[] *(elements+i);
delete[] elements;
elements=nullptr;
}
If i were to run the following code using this class:
Matrix exp1(2),exp2(2),exp3(2);
exp1.get_matrix();
exp3=exp1*exp2;
exp3.show_matrix();
I get a run-time error, while debugging i found out that, after the multiplication(exp1*exp2) the =operator was not able to access the data if the result of the *operator.
But if i were to use a manual destructor like this one at the end of the main() to free all allocated memory, the program works fine.
void destroctor()
{
for(int i=0;i<order;i++)
delete[] *(elements+i);
delete[] elements;
}
how can i edit the destructor or the operator overloads to correct this problem?
The constructor i used:
Matrix(int inp_order):order(inp_order)
{
elements=new int*[order];
for(int i=0;i<order;i++)
*(elements+i)=new int[order];
for(int i=0;i<order;i++)
for(int j=0;j<order;j++)
{
if (i==j)
*(*(elements+j)+i)=1;
else
*(*(elements+j)+i)=0;
}
}
It is hard to tell what is going wrong, since you have not posted your constructors.
In the exp3=exp1*exp2; a lot of things happen:
First a new matrix c is constructed in the operator* function. Then the return c; statement calls the copy constructor and then the destructor. After that operator= is called and after that the destructor for the temporary matrix again.
I think what happens is that you are using the default copy constructor which does not make a deep copy. That way the destructor being called at the time of return c deletes the data that still shared between the matrices.
I get a run-time error, while debugging i found out that, after the multiplication(exp1*exp2) the =operator was not able to access the data if the result of the *operator.
You didn't show us your constructor, so there is no way to tell why you are getting this errors.
I suspect that the cause is that you aren't allocating the memory needed to contain your matrix. You declared it as an int**, so you need to allocate an array of int* pointers, and for each of those you need to allocate an array of int.
Edit
While I was typing this you posted code for your constructor.
You are not returning a value from your overload of operator*, and you don't have a copy constructor (rule of three).
Do you have compiler warnings enabled? Any compiler worth its salt would have complained about the missing return statement in the operator overload.
You have not defined a copy constructor, so the compiler will generate one for you. This constructor will be called in order to copy the return value of operator*(const & Matrix a) into the result.
As the generated copy constructor only performs a shallow memberwise copy, it will not allocate a new array of elements, hence the error.