C/C++ Arena

Step 1 of 7

Copies are expensive

Copying a std::vector with a million elements copies a million elements. That's fine when you need two independent vectors. But very often the source is about to disappear anyway: it's a temporary, or a variable you'll never use again. Copying it and then throwing the original away is wasted work.

A move avoids that. Instead of copying the elements, the new vector simply takes over the old one's heap buffer (a pointer, a size and a capacity: three small values), and the old vector is left empty. It's like handing someone your suitcase instead of packing an identical one for them.

#include <iostream>
#include <string>
#include <utility>
#include <vector>

int main() {
    std::string a = "a long string that lives on the heap, not in the small buffer";
    std::string copy = a;                  // copies every character
    std::string moved = std::move(a);      // takes a's buffer

    std::cout << copy.size() << " " << moved.size() << "\n";
    std::cout << (copy == moved) << "\n";

    std::vector<std::string> shelf;
    std::string book = "Dune";
    shelf.push_back(book);                 // copy: we still use book below
    shelf.push_back(std::move(copy));      // move: done with copy
    std::cout << book << " | " << shelf.size() << "\n";
}
61 61
1
Dune | 2

lvalues and rvalues

C++ decides between copying and moving by looking at the kind of expression:

What std::move really does

std::move(x) doesn't move anything by itself. It's a cast that turns x into an rvalue, which means "I'm done with x, you may steal from it". The actual moving is done by whatever receives it: the vector's push_back, a constructor, an assignment.

After a move, the source is in a valid but unspecified state. Don't read its value. You may assign it a new one or let it be destroyed.

Your turn: move big into store instead of copying it.

Next: Write a move constructor