Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deep copy in a move constructor

Tags:

c++

c++11

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.

like image 386
M.Azzeddine Avatar asked Aug 31 '25 16:08

M.Azzeddine


1 Answers

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.

like image 117
Miles Budnek Avatar answered Sep 02 '25 07:09

Miles Budnek