The ability to move an object instead of copying always, is one of the most important features of C++11! Haven't yet come across a concise, interesting and a complete description of this feature, except the one from Thomas Becker: C++ Rvalues explained which goes systematically into this topic, doesn't touch every nook and recess of it, but gives you pointers in most cases. At places, he refers to the book by Scott Meyers Effective Modern C++, which to admit, I started reading, but still lingering at the first few articles. In this entry, I am pouring down whatever I have understood till now about this topic so to not forget about it and that I can reload it later (sort of like doing a 'git stash' now, to 'pop' later :-) ).
C++11 has introduced a proper and complete way to refer to the rvalues (literals or temporaries like the return values of functions etc.) in the program. Rvalues existed before C++11, but you could not refer to them completely in the program. C++03 allowed you to refer to an rvalue using a const lvalue reference, for example:
C++11 introduced rvalue references using which you can also modify the rvalues they are pointing to! An obvious question would be that why would you want to modify an rvalue which is usually a constant or a temporary object that's internally created by the compiler? The answer is that we may want to make use of the resources of the temporary object that's already created and save our CPU time to recreate it. The temporary object would anyway go waste otherwise. And that's the rationale behind the introduction of "moves" in C++11. So, now C++ has a new reference type (donated with '&&') using which you can declare names that can refer to rvalues. Also, the new type is handy is passing references to rvalues along a chain of function calls without any copying of actual values (also know "perfect forwarding").
In this post, I plan to experimentally show on how much performance improvement you can extract by using moves instead of copies. The example code can be seen at: compare.cpp. In the example, as you can notice, I define two classes MoveableSeq and NotMoveableSeq and as the name implies the former has a move constructor, while the latter doesn't have one. Both these classes define an array of 1000 values which is dynamically allocated at the construction time. To compare the two, I create a std::vector of objects of both these classes. For NotMoveableSeq, the objects are copied into the vector, while for MoveableSeq, the objects are moved into the vector. There is also a third scenario where the objects are "emplaced" into the vector i.e. they are directly created inside the vector, thus involving neither a copy, nor a move. For comparison, I collect the time taken for objects number starting from 1000 to 250K and plot the graph for all the three cases, as shown below. The result is as you would expect - nothing to explain further! The code to plot this graph was done using python and it is uploaded at the same github location as compare.cpp.
C++11 has introduced a proper and complete way to refer to the rvalues (literals or temporaries like the return values of functions etc.) in the program. Rvalues existed before C++11, but you could not refer to them completely in the program. C++03 allowed you to refer to an rvalue using a const lvalue reference, for example:
template<typename T>
std::string to_string(const T& ob)
{
std::string tmp = ...;
return tmp;
}
void print_string(std::string& s); // (1)
void print_string(const std::string& s); // (2)
print_string(to_string(4));
If only print_string (1) is available, then the compiler would give an error saying that it could not find a suitable candidate for the call to print_string. With print_string(2) being present, everything would go fine. The reason is print_string is being called with an rvalue and it cannot be referred using an lvalue_reference as in (1), but can be referred using a const lvalue reference as in (2). So, you could refer to rvalues in C++03 too, but it was not complete in the sense that you could not modify the rvalue using that reference (as it was a const reference).C++11 introduced rvalue references using which you can also modify the rvalues they are pointing to! An obvious question would be that why would you want to modify an rvalue which is usually a constant or a temporary object that's internally created by the compiler? The answer is that we may want to make use of the resources of the temporary object that's already created and save our CPU time to recreate it. The temporary object would anyway go waste otherwise. And that's the rationale behind the introduction of "moves" in C++11. So, now C++ has a new reference type (donated with '&&') using which you can declare names that can refer to rvalues. Also, the new type is handy is passing references to rvalues along a chain of function calls without any copying of actual values (also know "perfect forwarding").
In this post, I plan to experimentally show on how much performance improvement you can extract by using moves instead of copies. The example code can be seen at: compare.cpp. In the example, as you can notice, I define two classes MoveableSeq and NotMoveableSeq and as the name implies the former has a move constructor, while the latter doesn't have one. Both these classes define an array of 1000 values which is dynamically allocated at the construction time. To compare the two, I create a std::vector of objects of both these classes. For NotMoveableSeq, the objects are copied into the vector, while for MoveableSeq, the objects are moved into the vector. There is also a third scenario where the objects are "emplaced" into the vector i.e. they are directly created inside the vector, thus involving neither a copy, nor a move. For comparison, I collect the time taken for objects number starting from 1000 to 250K and plot the graph for all the three cases, as shown below. The result is as you would expect - nothing to explain further! The code to plot this graph was done using python and it is uploaded at the same github location as compare.cpp.
