rvalue references are designed with two aims in mind:
- move semantics
- perfect forwarding
Move semantics
One purpose of move semantics, in general, is an optimization of copy. Where you can copy, you can just move the resources held by the object.
std::string str("The quick brown fox jumps over the lazy dog.");
std::cout << str; // Do something
func(std::move(str)); // You do not need str in the subsequent lines, and so move
Also, the compiler can optimize the return value of a function, where RVO may not be applicable
std::vector<std::string> read_lines_from_file(const std::string& filename);
auto lines = read_lines_from_file("file1.txt"); // Can possibly be optimized with RVO
// Do something with lines
lines = read_lines_from_file("file2.txt"); // RVO isn't applicable, but move is
// Do something with lines
If you implement move semantics in your classes, chances are you will experience a significant performance boost when you are putting them in containers. Consider std::vector
. Whenever you modify the elements of an std::vector
, at some time, some reallocations and element shifting would happen. In C++98, elements are mostly copied around[1], which is unnecessary, as there is logically only one representation of the object that is needed at a single point of time. With move semantics, containers like std::vector
can just move the objects around, eliminating extra copies and therefore boost the performance of your program.
One very important use of move semantics is not just for optimization but for implementing unique ownership semantics. One very good example is std::unique_ptr
in which it can only be moved around (it cannot be copied), therefore you are guaranteed (with proper use) that there is only one std::unique_ptr
that is managing the contained pointer or resource.
Perfect forwarding
Perfect forwarding uses rvalue references and special template deduction rules for us to be able to implement perfectly forwarding functions, that is, functions that can forward arguments correctly and without making any copies.
Examples are std::make_shared
and the upcoming std::make_unique
. Also are the new emplace*
methods of containers, one that you will find very useful and convenient (not mentioning that it would also be very efficient).
This answer provides a very good and thorough explanation of rvalue references with respect to move semantics and perfect forwarding.
[1] One thing I heard from one of Bjarne Stroustrup's talk[source needed] is that containers typically implement some ad-hoc move semantics. Therefore, as he has said, you may not experience that much of a speed-up.