Move semantics concerns avoiding unnecessary copies whenever possible.
The compiler knows that temporary objects (for example, vector.push_back(getData())) can be copy-elided. In unapparent cases, we use std::move() to tell the compiler that the object is “no longer needed” and “its content can be stolen/moved” (i.e. the ownership is moved).
Sometimes it makes sense to reuse object after moved:
std::vector<std::string> rows;
std::string row;
while(std::getline(std::cin, row)) {
rows.push_back(std::move(row));
}
With rvalue references (double &), programmers can define move logic for objects.
Rules of 5: all or nothing: destructor, copy constructor, copy assignment constructor, move constructor, move assignment constructor
// only “objects with no name” (i.e. temp objects) or std::move()
void foo(T&& obj)
// compiles but useless because obj is not needed but we cannot
// modify or steal data!
void foo(const T&& obj)
If no move semantics is provided, copy semantics is used. But we can disable this copy fallback behavior (this is used by move-only objects, e.g. std::thread, std::unique_ptr).
By default, move semantics is defined for objects. However it is disabled if any special member function (destructor, copy constructor, assignment operator) exists.
For polymorphism hierarchy, a declared virtual destructor also disables move semantics (for the members of the objects…)
The act to forward arguments while preserving their value categories.
Note that:
void foo(const T&& obj) {
// inside here obj is no longer interpreted as rvalue reference (move semantics lost)
// there calling vector.push_back(obj); would be copying
// if we want to move, need vector.push_back(std::move(obj));
}
Perfect forwarding of parameters needs: