C++ and move semantics and perfect forwarding
Move semantics makes it possible for compilers to replace expensive copying operations with less expensive moves. In the same way that copy constructors and copy assignment operators give you control over what it means to copy objects, move constructors and move assignment operators offer control over the semantics of moving. Move semantics also enables the creation of move-only types, such as std::unique_ptr
, std::future
, and std::thread
.
Perfect forwarding makes it possible to write function templates that take arbitrary arguments and forward them to other functions such that the target functions receive exactly the same arguments as were passed to the forwarding functions.
At runtime, neither does anything at all. They generate no executable code. Not a single byte.
What happens during swap method
template<typename T>
void foo(T& a, T& b) {
auto tmp = a;
a = b;
b = tmp;
}
What happens:
What we expect to happen:
Observations:
- no need to copy contents from
a
totmp
- no need to copy contents from
b
totmp
a
’s copy insidetmp
is no longer needed at the end
We need:
- a way to move the internal states of objects
- a way to express „this is object is temporary/can be recycled”
- to overload funtions / constructors / … for such temporaries
std::move
After using std::move
we expect to have some perfomance gain if T
is cheaply movable.
Almost all standard containers are cheap to move (std::array
is not).
template<typename T>
void foo(T& a, T& b) {
auto tmp = std::move(a);
a = std::move(b);
b = std::move(tmp);
}
lvalue and rvalue
lvalue = expression of which we can take its memory address
rvalue = expression of which we cannot take its memory address
Original meaning: (l/r) values on (left/right) hand side of assignment
auto x = std::make_unique<int>(5);
std::unique_ptr<int> y;
y = std::move(x);
rvalue references
lvalue references:
T&
– bind to non-const lvalues of typeT
onlyT const&
– bind to const lvalues and rvalues of typeT
rvalue references:
T&&
– bind to rvalues of typeT
only
std::move and rvalue
So now we can say that std::move
casts an expression to an rvalue.
void foo(int& x);
void bar(int const& x);
void baz(int&& x);
int i = 0;
foo(i); // OK
foo(std::move(i)) // ERROR: lvalue ref cannot bind to rvalue
bar(i); // OK
bar(move(i)); // OK
baz(i); // ERROR: rvalue ref cannot bind to lvalue
baz(std::move(i));// OK
Overview of Special Member Functions
class T {
T(); // Default Constructor
T(std::initializer_list<...>); // Initializer List Constructor
~T(); // Destructor
T(T const&); // Copy Constructor
T& operator=(T const&); // Copy Assignment Operator
T(T&&); // Move Constructor
T& operator=(T&&); // Move Assignment Operator
}
std::forward
The story for std::forward
is similar to that for std::move
, but whereas std::move unconditionally casts its argument to an rvalue, std::forward does it only under certain conditions. std::forward
is a conditional cast.
std::forward
casts its argument to an rvalue only if that argument is bound to an rvalue.
Reference:
https://hackingcpp.com/cpp/lang/move_semantics.html
Other cpp articles from my site: