This is probably just me being stupid somehow or the other, but I am relatively new to C++, so forgive me the idiocy. I’m trying to teach myself how to use operators. I’ve defined a very basic operator as follows:
Matrix::Matrix operator+(Matrix a1, Matrix a2) {
if(a1.rows != a2.rows || a1.cols != a2.cols) {
std::cout << "ERROR: Attempting to add matrices of non-equal size." << std::endl;
exit(6);
}
int i, j;
Matrix c(a1.rows, a1.cols);
for(i = 0; i < a1.rows; i++)
for(j = 0; j < a1.cols; j++)
c.val[i][j] = a1.val[i][j] + a2.val[i][j];
return c;
}
The class Matrix represents a matrix, and has a constructor that takes two ints as input (the number of rows and columns in the matrix, respectively), and creates a 2D array of doubles of the appropriate size (named val). This function works as supposed to in that the value for c is correct, but it also appears to destruct a1 and a2. That is, if I write
Matrix c = a + b;
It gives the right result, but a and b are no longer usable, and I get a glibc error at the end of the code claiming I am trying to destruct a and b when they have already been destructed. Why is this?
Your signature is wrong:
it should be
The reason it appears to destroy
a1anda2is because, well, it is, since those are temporary copies created in the method scope.If the original values are destroyed, you’re probably violating the rule of three. When
a1anda2are destroyed, the destructor gets called, and you’re probably deleting pointers in the destructor. But since the default copy constructor does only a shallow copy, the copieda2anda1will delete the original memory.Edit: Since there are split opinions about this, I’ll extend my answer:
Assume:
In this first example, the copy constructor is not implemented.
A copy constructor is generated by the compiler. This copy constructor copies
xinto the new instance. So if you have:Important note that the pointers are the same.
Calling
option 1will create copies insideoperator +, because the values are passed by value:When
operator +exits, it will calldelete xon objectsa1anda2, which will delete the memory that is also pointed to bya.xandb.x. That is why you get the memory corruption.Calling
option 2however, since no new objects are created because you pass by reference, the memory will not be deleted upon function return.However, this isn’t the cleanest way to solve the issue. It solves this issue, but the underlying one is much more important, as Konrad Pointed out, and I have in my original answer (although haven’t given it enough importance, I admit).
Now, the correct way of solving this is properly following the rule of three. That is, have an implementation for
destructor,copy constructorandassignment operator:With this new code, let’s re-run the problematic
option 1from before:Because the copies
a1anda2now point to different memory locations, when they are destroyed, the original memory is intact and the original objects –aandbremain valid.Phew! Hope this clears things up.