There are several situations that either you keep doing specific manipulations to avoid data copying or you allow these copies to be made creating a performance cost.
This usually occurs in types where the value type semantics is desired (see more on the subject in that and in that answer, is another language but the idea is the same) that are normally stored in stack or as an integral part of another object in heap. In other words, you work effectively with the data value and not with a reference to the actual value. But to avoid the cost of copying these values some types are accessed by reference - through a pointer - maintaining their value semantics. String is a very typical case.
It is true that some types can be optimized by the compiler and this happened with string, for example. But the compiler does not know all types. It was necessary to allow each type to be defined in such a way that the optimization was always done.
With the std::move
it is possible to move a value to another reference. This is done through a pointer, it is very cheap.
One might be wondering, why do you need to move? Why don’t you copy it like you always did in C++? The problem with copying is that it retains property of the object (value).
When you have value semantics, you never have two or more references to an object (a value) because it is self-referenced, the value exists by itself. When you copy the value, the copy is another object and has another owner (a variable, for example). Although initially the values are equal, they happen to be two completely different and independent objects.
You want to ensure that these types that have reference but use value semantics also do not have more than one owner. A simple copy would create a new reference for the object. This has implications in concurrent execution environments and would complicate automatic memory management because it would have to control how many references the object has and only when it has zero should the object be destroyed.
As the possibility to move, we are indicating to the compiler that the object can only have one owner, which is not like two owners to try to access the object simultaneously and does not need control how many owners have. This greatly simplifies everything that has to be done in your code and what the compiler has to generate to control the lifetime of the object.
It has always been possible to do this, but now it has a standardized form and that the compiler can benefit since it is standard. He can make decisions based on this.
In practice this std:move
disappears from code after compiled. It does serve to inform how the compiler should handle it.
This made it possible to create the std:unique_ptr
which greatly simplified automatic memory management without implicating in overhead processing or memory. And this is a revolution for C++.
Its implementation is very simple, it’s like this:
template <class T>
typename remove_reference<T>::type&&
move(T&& a) {
return a;
}
Example of use:
template <class T> swap(T& a, T& b) {
T tmp(a); //a passa ter duas referências p/ "a", a original que passou o parâmetro e aqui
a = b;//e agora duas cópias para "b"
b = tmp; //mais um cópia para "tmp" que já é cópia para "a"
}
See the difference:
template <class T> swap(T& a, T& b) {
T tmp(std::move(a)); //nenhuma cópia é feita em nenhum do casos, só ponteiros se movimentam
a = std::move(b);
b = std::move(tmp);
}
I put in the Github for future reference.
When you use the std:move
the variable is giving up the property of the object. Which can be given back by the new owner.
Surely there is much more to talk about. And all I have said is a simplification.
Reference in Wikipedia.
Pre-official documentation.
I think I’m beginning to understand. But what would happen if I did something like: b = Std::move(a); a->foo(); This would cause a fatal error?
– jlHertel
No. This is exactly why you have the
move
. The compiler knows what to do in such cases. All this semantics is just to make the compiler aware of what it can and cannot do. In this casea
andtmp
are the same thing. Both work. Essentially themove
does not change the way to do anything, changes the internal way the compiler handles it. This is just extra information for the compiler to handle your data better. Perhaps seeing is easier to understand. Look what I did: http://ideone.com/L3t9Hb– Maniero