Lesson 130 +10 XP

Move Semantics and std::move

Move Semantics and std::move

Copying data is wasteful when you only want to transfer it. Move semantics lets you transfer resources without copying everything.

Lvalue vs rvalue

  • An lvalue is an object you can take an address of: int a = 5;, a is an lvalue.
  • An rvalue is a temporary that is about to die: the result of a function call like foo() or the literal 5.

Rvalue references

An rvalue reference is written with &&. It binds only to rvalues:

void set(std::string&& src);   // only accepts rvalues

That lets you distinguish "give me a temporary to steal" from "give me one you still need."

Move constructor and move assignment

A move constructor accepts an rvalue reference and steals the other object's resources, leaving it empty:

class Buffer {
    int* data;
public:
    Buffer(Buffer&& other) : data(other.data) {
        other.data = nullptr;   // steal and clear the source
    }
};

The source ends up empty but valid. This is O(1); copying the large array would be O(N).

std::move

std::move casts an lvalue into an rvalue reference so the move path is chosen from now on:

std::string a = "hello";
std::string b = std::move(a);   // b steals a's data

b now owns the string; a is left in a valid but unspecified state.

When it happens automatically

The compiler picks the move constructor whenever you return a local, pass a temporary, or construct from one. For special classes with heavy data, moves make everything fast without you writing a line. A vector's growth also reuses moves, so push_back of a temporary moves.

TL;DR

  • rvalue references && bind only to temporaries.
  • A move constructor steals resources cheaply from the source.
  • std::move forces the move for an lvalue.
  • Moving is much cheaper than copying a big buffer.
  • First-class situations (returning temporaries) are chosen automatically.