0%

practice of using move and forward

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Widget {
public:
Widget(Widget&& rhs)
: name(std::move(rhs.name))
, p(std::move(rhs.p)) {}

private:
std::string name;
std::shared_ptr<SomeDataStructure> p;
};

class Widget {
public:
template<typename T>
void setName(T&& newName) {
name = std::forward<T>(newName);
}
};

Widget makeWidget() {
Widget w;
...
return std::move(w); // DO NOT DO THIS!
}

Widget w1;
Widget w2 = std::move(w1); // w1 is "empty"
Widget &&w3 = std::move(w2); // w3 is an rvalue reference and an lvalue, no type deduction
void f(Widget &&w) {
// modify w
}
f(w3); // compilation error! w3 is an lvalue
f(std::move(w3)); // Okay! modifying w inside f changes w3

Conclusion:

  • use std::move to rvalue references and std::forward to universal references the last time each is used
  • Do the same thing for rvalue references and universal references being returned from functions that return by value
  • Never apply std::move or std::forward to local objects if they would otherwise be eligible for the return value optimization (RVO)
  • std::move performs an unconditional cast to an rvalue. In and of itself, it doesn’t move anything
  • std::forward casts its argument to an rvalue only if that argument is bound to an rvalue
  • Neither std::move nor std::forward do anything at runtime