We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Copy, Move, and the Rule of Zero step 2 of 5
std::move does not move anything
The name is a lie and it has cost the industry a lot of time.
template <typename T>
constexpr std::remove_reference_t<T>&& move(T&& t) noexcept {
return static_cast<std::remove_reference_t<T>&&>(t);
}
That is the entire implementation. std::move is a cast. It generates no
instructions, transfers nothing, and leaves its argument exactly as it was.
What it does is change what the next line is allowed to do. Casting to an rvalue reference makes the expression eligible for the move constructor or move assignment operator, and it is that function — written by the author of the type — which actually steals the pointer and leaves the source empty.
std::moveis a request for permission. The move happens in the constructor that accepts it, or it does not happen at all.
Three ways the request is silently denied
1. The source is const.
const Payload& p = items[0];
out.push_back(std::move(p)); // casts to const Payload&&
A move constructor takes Payload&&; a const Payload&& cannot bind to it.
Overload resolution falls back to the copy constructor, which takes
const Payload& and accepts anything. The code compiles, says move, and
copies. This is the most common of the three and the hardest to see.
2. The destination takes const&.
void store(const Payload& p);
store(std::move(payload)); // copies inside store, if it copies at all
There is no move overload to select, so the cast selects the same function it would have anyway.
3. The type has no move operations. Then there is nothing to select and every “move” is a copy. Track 3.4 is about when that happens.
And one place you should not write it
return std::move(local); // worse than `return local;`
Returning a local by name already moves — better, it usually elides the
move entirely and constructs the value directly in the caller. Writing
std::move there turns an expression the compiler could elide into one it
cannot, so the “optimisation” makes it slower. Return the name.
Your task
std::vector<Payload> take(std::vector<Payload>& parts, int limit);
Move the first limit payloads out of parts into a new vector and return
it. If limit exceeds the size, take everything; if it is zero or less, take
nothing. parts keeps its size — you are emptying elements, not erasing them.
The starter already calls std::move and still copies every element, which
is the lesson stated as a bug. Payload counts its copies and the harness
prints the count; get it to zero.
Run the gate when you are stuck. performance-move-const-arg names the line
and explains itself better than most compiler messages.
Stuck?
C++ reference solution
Sign in to attempt this problem and reveal the reference solution.