I am new to C++11 so i still strugle with its concepts.
Here's my problem :
I have a matrix class :
class matrix
{
private:
double** data;
size_t number_lines;
size_t number_columns;
size_t capacity_lines;
size_t capacity_columns;
public:
....
}
and i've provided a copy constructor, a move constructor...
I've overloaded the multiplication operator *(double x) to multiply matrix elements by the scalar x and return the multiplied matrix. Here's the code :
matrix matrix::operator*(double lambda)
{
double** aux_data = new double*[number_lines];
for (size_t i = 0; i < number_lines; i++)
{
aux_data[i] = new double[number_columns];
for (size_t j = 0; j < number_columns; j++)
aux_data[i][j] = lambda*data[i][j];
}
return matrix(aux_data, number_lines, number_columns);
}
the return of the function is an rvalue reference so it invokes the move constructor. Here's the code of the move constructor :
matrix::matrix(const matrix&& moved_copy)
{
if (this != &moved_copy)
{
number_columns = moved_copy.number_columns;
number_lines = moved_copy.number_lines;
data = moved_copy.data;
}
}
The problem with this move constructor is that it performs a shallow copy and not a deep copy (like every move constructor i guess, otherwise what's the point of this move constructor) so the member data points to the object pointed by moved_copy.data, but this object is local to the operator *=() function so when the operator goes out of scope the object is gone and i have a dangling pointer. So my question is : should i perform a deep copy in the move constructor or is there way of solving this problem without doing so ?
Thank you.
No, you shouldn't make a deep copy in a move constructor. The whole point of a move constructor is to take ownership of some resource that's expensive to copy.
In this case, ownership of your data
pointer can be transferred from an existing matrix
to the newly constructed matrix
object. But the idea is to transfer ownership, to the new object, not to share ownership with the new object. In this case that just means setting moved_copy.data
to nullptr
, that way it won't delete your data
when it's destroyed.
matrix::matrix(matrix&& moved_copy)
{
number_columns = moved_copy.number_columns;
number_lines = moved_copy.number_lines;
data = moved_copy.data;
moved_copy.data = nullptr;
}
Notice that I also removed your if
guard: there's no way to construct an object from itself, so that's not really needed for a move constructor (it can be useful for a move assignment operator though).
I also removed the const
from moved_copy
. Move constructors need to modify the state of the moved-from object to take ownership of its resources, so const
cant' be used.
Edit: It is actually possible to construct an object from itself, but it's not something that you really need to guard against.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With