Skip to content

Introduction to Move Semantics

Beginning of the lesson

Introduction to Move Semantics

Stop copying what you can steal — how modern C++ moves resources instead of duplicating them.

Big Idea: When an object owns an expensive resource (a heap buffer, a file handle, a large std::vector), copying it duplicates that resource byte for byte. A move instead transfers ownership of the existing resource to a new object and leaves the old one empty. Same result, a fraction of the work. Move semantics is the language feature (added in C++11, refined ever since) that makes this safe and automatic.
By the end you will be able to:
  • tell an lvalue from an rvalue and explain why the distinction matters,
  • describe what a copy costs and how a move avoids it,
  • use std::move correctly — and explain that it does not, by itself, move anything,
  • reason about the state of an object after it has been moved from,
  • recognise where the compiler moves for you automatically (returns, inserting into containers).

1. lvalues vs rvalues: does it have a name you can point at?

Every expression in C++ is either an lvalue or an rvalue (there are finer categories, but these two carry the intuition). The names come from the sides of an assignment: historically an lvalue could appear on the left of = and an rvalue only on the right.

  • An lvalue is an object with a stable identity — a named location in memory you can take the address of. Variables are lvalues: x, account.balance, numbers[3].
  • An rvalue is a temporary value with no lasting name — the result of an expression that is about to disappear. Literals and the results of most expressions are rvalues: 42, a + b, std::string("hi"), the value returned by a function.

The practical test: if you can take its address with &, it is an lvalue; if you cannot, it is an rvalue.

int x = 10;
int& a = x;          // OK: x is an lvalue, it has an address
// int& b = 10;      // ERROR: 10 is an rvalue, no address to bind to
int&& c = 10;        // OK: an rvalue REFERENCE can bind to the temporary 10
int&& d = x + 5;     // OK: (x + 5) is a temporary rvalue

That last piece of syntax — int&&, a double ampersand — is an rvalue reference. It is a reference that only binds to rvalues (temporaries). This is the hook move semantics hangs on: a function can offer one overload for const T& (binds to anything, promises not to change it) and another for T&& (binds only to temporaries the caller no longer needs). When the second one is chosen, the function knows it is safe to gut the argument.

Why does "no lasting name" matter? Because if a value is a temporary that is about to be destroyed anyway, no one will ever notice if we quietly empty it. That permission is exactly what makes moving safe.

Continue this lesson on YourAIZone

The full lesson has the complete explanation, worked examples, common mistakes, tests with instant checking and an AI tutor. Start right away as a guest, or create an account to keep your progress.

In the full lesson

  • The complete explanation
  • Worked examples
  • Common mistakes and how to avoid them
  • Test questions: 15
  • AI tutor that answers questions about the topic
  • Progress tracking for students, parents and teachers