I've been reading up on move semantics lately and how it was introduced into C++11. The main gist is that programs could become more efficient by creating objects by 'stealing' pointers to temporary objects. This is much more efficient than doing a deep copy of the temporary object to create new objects.
In C++11 (and onward), this is achieved with the use of rvalue references. All temporary objects (objects that don't have a known place within your programs memory) are considered rvalues. Specifically, class constructors could now be overloaded to accept rvalue references.
So I'm curious, how was this problem of 'expensive temporary object copy' addressed prior to C++11?
Move semantics is a set of semantic rules and tools of the C++ language. It was designed to move objects, whose lifetime expires, instead of copying them. The data is transferred from one object to another. In most cases, the data transfer does not move this data physically in memory.
Move Semantics is an extremally important concept for one to understand talking about programming in c++. It is a fundamental aspect of the language that may not be that obvious and even more for one coming from another language such as Swift, C#, or Java.
“l-value” refers to a memory location that identifies an object. “r-value” refers to the data value that is stored at some address in memory. References in C++ are nothing but the alternative to the already existing variable. They are declared using the '&' before the name of the variable.
That's pretty much the only time you should write std::move , because C++ already uses move automatically when copying from an object it knows will never be used again, such as a temporary object or a local variable being returned or thrown from a function. That's it.
The main way this was done was via std::swap
. std::swap
could be overloaded/specialized for types where it could be executed more efficiently than the default "swap via a temporary variable" to instead perform a shallow swap.
Often data types would provide a swap()
member function that could be used by this overload to access the private internals of the data type. (For example; see std::vector::swap)
For example; to "move" an element into a vector
, the following code could be used:
class MyListOfVectors {
private:
//using `std::vector<int>` as an example of a "movable" type.
std::vector<std::vector<int>> list;
public:
void emplace_back(std::vector<int> &n) {
using std::swap;
list.push_back(std::vector<int>());
swap(list.back(), n);
//(possibly add something to rollback the `push`
// in case swap fails; to provide the strong
// exception guarantee)
}
};
To return an element via "move", the following code could be used:
std::vector<int> MyListOfVectors::pop_back() {
using std::swap;
std::vector<int> r;
swap(list.back(), r);
list.pop_back();
return r; //Trust in copy elision to avoid any actual copies.
}
I don't have a reference for this, but I believe standard algorithms were allowed/encouraged to use std::swap
for this purpose.
Also, if you were feeling like you wanted to do things the C++11 way, you could also use boost::move, which provides an emulation of the C++11 move semantics in C++03 (though it technically violates strict aliasing and so has undefined behavior).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With