3

What exactly is the purpose of this "move" semantic? I understand if you don't pass in by reference a copy is made of non-primitive types, but how does "move" change anything? Why would we want to "move" the data? Why cant it just be kept at the same address and not copied? If it is sent to another address, isn't this just a "copy and delete"?

In short, I don't really get what move semantics is achieving exactly.

intrigued_66
  • 16,082
  • 51
  • 118
  • 189

3 Answers3

2

Move semantics combines the advantages of passing by value and passing by reference. You allocate classes statically, so you don't have to take responsibility for their lifetime, and you can pass them as parameters and return from functions easily. On the other hand, in the case, when ordinarily objects would have been copied, they are moved (only their internals are copied). This operation may be implemented a lot less time-costlier than copying (because you do know, that rhs object won't be used anymore).

MyObj * f()
{
    // Ok, but caller has to take care of
    // freeing the result
    return new MyObj();
}

MyObj f()
{
    // Assuming, that MyObj does not have move-ctor
    // This may be time-costly
    MyObj result;
    return result;
}

MyObj f()
{
    // This is both fast and safe
    MyObj result;
    return std::move(result);

    // Note, if MyObj implements a move-ctor,
    // usually you don't have to call std::move.
}
Spook
  • 25,318
  • 18
  • 90
  • 167
1

Why cant it just be kept at the same address and not copied

This is actually what move semantics generally does. It often keeps the resource (often memory, but could be file handles, etc.) in the exact same state, but it updates the references in the objects.

Imagine two vectors, src and dest. The src vector contains a large block of data which is allocated on the heap, and dest is empty. When src is moved to dest all that happens is that dest is updated to point to the block of memory on the heap, whilst src is updated to point to whatever dest was pointing to, in this case, nothing.

Why is this useful? Because it means that vector can be written with the confidence that only one vector will ever point to the block of memory it allocates. This means that the destructor can ensure that it cleans up the memory that has been allocated.

This can be extended for objects which manage other resources, such as file handles. It is now possible to write objects that can own a file handle. These objects can be movable, but not copyable. Because STL containers support movable objects, these can be put into containers far easier than they could in C++03. They file handle, or other resource, is guaranteed to only have on reference to it and the destructor can close it appropriately.

Steve
  • 7,171
  • 2
  • 30
  • 52
0

I'd answer with a simple example for vector algebra:

class Vector{
  size_t dim_;
  double *data_;
public:
  Vector(const Vector &arg)
    : dim_(arg.dim_)
    , data_(new double[dim_])
  {
    std::copy_n(arg.data_, dim_, data_);
  }

  Vector(Vector &&arg)
    : dim_(arg.dim_)
    , data_(arg.data_)
  {
    arg.data_ = nullptr;
  }

  ~Vector()
  {
    delete[] data_;
  }

  Vector& operator+= (const Vector &arg)
  {
    if (arg.dim_ != dim_) throw error;
    for (size_t idx = 0; idx < dim_; ++idx) data_[idx] += arg.data_[idx];
    return *this;
  }
};

Vector operator+ (Vector a, const Vector &b)
{
  a += b;
  return a;
}

extern Vector v1, v2;

int main()
{
  Vector v(v1 + v2);
}

The addition returns a new vector by value. As it's an r-value, it will be moved into v, which means that no extra copies of the potentially huge array data_ will happen.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455