1. Definition: l-values vs r-values
l-values
l-values can appear on the left or right of an =. l-values have names, and are not temporary. l-values live until the end of the scope.
r-values
r-values can only appear on the right of an =. r-values don’t have names, and are temporary. r-values live until the end of the line.
Only l-values can be referenced using &
.
1 | int main(){ |
How many arrays will be allocated, copied and destroyed here?
1 | int main(){ |
- vec is created using the default constructor.
- make_me_a_vec creates a vector using the default constructor and returns it.
- vec is reassigned to a copy of that return value using copy assignment.
- copy assignment creates a new array and copies the contents of the old one.
- the original return value’s lifetime ends and it calls its destructor.
- vec’s lifetime ends and it calls it destructor.
2. Move Assignment
Copy assignment creates a new array and copies the contents of the old one…what if it didn’t? Let’s call this move assignment.
When the item on the right of the = is an r-value, we should use move assignment. Why? r-values are always about to die, so we can steal their resources. How? using
&&
for r-value reference.
Overloading with &&
1 | void change(int&& num){...} // version 1 takes r-values |
We can steal the array:
1 | vector<T>& operator=(vector<T>&& other){ |
Also, we can force move assginment rather than copy assignment of these ints by using std::move(x)
, it doesn’t do anything except cast x as an r-value.
The compiler will pick which version(copy or move) to use based on whether the RHS is an l-value or an r-value. std::move(x)
is a way to force C++ to choose the && version of a function.
1 | vector<T>& operator=(vector<T>&& other){ |
Where else should we use std::move
?
Rule of thumb: wherever we take in a
const&
parameter in a class member function and assign it to something else in our function.
Copy push_back:
1 | void push_back(const T& element){ |
Move push_back:
1 | void push_back(T&& element){ |
Be careful with std::move
, after a variable is moved via std::move
, it should never be used until it is reassigned to a new variable!
Don’t use
std::move
outside of class definitions, never use it in application code!
TLDR: Move Semantics(语义)
- If your class has copy constructor and copy assignment defined, you should also define a move constructor and move assignment.
- Define these by overloading your copy constructor and assignment to be defined for
Type&& other
as well asType& other
. - Use
std::move
to force the use of other types’ move assignments and constructors. - All
std::move(x)
does is cast x as an r-value. - Be wary of
std::move(x)
in main function code!
std::move
and RAII
- RAII means all resources required by an object are acquired in its constructor and destroyed in its destructor.
- To be sonsistent with RAII, you should have no half-ready resources, such as a vector whose underlying array has been deallocated.
std::move
doesn’t consistent with RAII.
- 本文作者: 夏花
- 本文链接: http://xiahua19.github.io/2022/07/26/cs106l-12-Move-Semantics-in-C/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!