Intermediate C++ Game Programming Tutorial 20
In this video we learn about r-value reference and move semantics, which is perhaps the most important feature that was added in the C++11 update. This is going to allow us to manage and transfer our resources in a precise and efficient manner. It is sexy as fuck and I love it.
Topics Covered
- r-values and l-values
- r-value reference function overloading
- Move constructor and move assigment
- Rule of 5
-
std::move
-
std::make_move_iterator
Video Timestamp Index
- Why are move semantics important and required? 0:23
- What is an rvalue (simple definition) 2:48
- Why is the distinction between rvalues and lvalues useful? 4:57
- Overloading a function to take an rvalue reference using
&&
6:11
-
std::move()
: Converting a variable into an rvalue reference 8:00
- Move constructor and Move assignment 10:07
- Implementing the move constructor and move assignment operator in the
Surface
class of the Sprite drawing project 11:09
- The full story on implicit compiler definition of special member functions and the "Rule-of-5" 14:22
- If you implement any of the special member functions, you should implement all of them:
- - Destructor
- - Copy constructor
- - Copy assignment
- - Move constructor
- - Move assignment
- The behavior of the default move members and the "Rule-of-0" 15:17
- If a class only contain data members (Types) that handle their own RAII behavior (such as the STL containers), then you don't need to supply any move member functions
- If a function is called on an STL container, you don't need to specify move semantics, the container implementation takes care of it.
- - No need for a function overload of
void SomeFunc(std::string&& donor)
.- if the default function is defined as
void SomeFunc(const std::string& str)
,
just use a singlevoid SomeFunc(std::string str)
that takes (in this example) a string by value
- if the default function is defined as
- - If an lvalue is passed as the argument, the string will be copied into the local variable
- - If an rvalue is passed as the argument, the string will be move the data into the local variable
- Fix the
Surface
class to include the case (or: the state) where a surface is empty 19:09- This has become necessary because the a move operation will leave the donor object empty
- Using a
std::make_move_iterator
to apply thestd::copy_if
algorithm to act as a "move-if" operator on containers 21:00- The
make_move_iterator
is a convenience function that constructs astd::move_iterator<Iter>(i)
which can be used to move out from the elements accessed through the input iteratori
- Example code written to move strings from a vector of strings when they are larger than a certain threshold
- The
Note
If you are using Visual Studio 2017, you might notice that our move members are not being used during std::vector
growth even after we have 'properly' implemented them. This is expected, so don't pay it much mind at the moment.
The reason for this is that std::vector
will only use the move members if they are guaranteed not to throw any exceptions (as per the standard). This issue will be dealt with in Intermediate 22 (tutorial on exceptions). For your interest, you can enable the move optimization by declaring your move ctor as Surface( Surface&& ) noexcept
. The same should be done for the move assignment and the destructor.
You might wonder why Chili had no problems in the video. In the video, Chili was using Visual Studio 2015, which does not conform to the standard in this point, so it uses the move members regardless of whether or not they are marked noexcept
.