LESSON 11 · BEGINNER4 min read

Move Semantics, Rvalue References, and the Rule of Five

Master modern C++ resource ownership: move constructors, move assignment operators, noexcept contracts, std::move casts, and the canonical Rule of Five.

C++20 / C++23Free to readModule 3 of 11
YOUR NEXT SMALL WINS

By the end, you’ll be able to…

  • Synthesize move constructors and move assignment operators that transfer heap ownership in O(1) time
  • Explain why move constructors must be marked noexcept to enable std::vector reallocation guarantees
  • Apply the Rule of Five (Destructor, Copy Ctor, Copy Assign, Move Ctor, Move Assign) and Rule of Zero

01The Motivation for Move Semantics

Prior to C++11, returning a large container (such as a 1GB std::vector or large string) from a function or passing a temporary into a collection required a deep copy. A deep copy allocates a brand-new heap buffer, copies millions of bytes across the CPU memory bus, and then immediately destroys the original temporary object—wasting millions of clock cycles.

C++11 introduced Move Semantics via Rvalue References (T&&). Instead of copying resources from an object that is about to be destroyed (a temporary or expiring xvalue), we can 'steal' its resources in O(1) time.

A move operation simply copies the internal raw pointer address from the source object, updates size fields, and resets the source object's pointer to nullptr. When the source object later destructs, delete[] nullptr is an operational no-op, leaving the stolen memory intact under the new owner.

example.js⚙️C++
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.

02Why Move Constructors MUST Be Marked 'noexcept'

One of the most critical rules in systems C++ is: Always mark move constructors and move assignment operators noexcept.

Consider what happens when a std::vector<T> grows and must reallocate its internal buffer to double capacity: it allocates a larger array and moves existing elements from the old array to the new array.

If an element's move constructor could potentially throw an exception midway through the reallocation, the vector cannot roll back the move without data loss (the moved-from elements are already modified). To uphold the Strong Exception Guarantee, std::vector checks std::is_nothrow_move_constructible<T>::value.

If the move constructor is NOT marked noexcept, std::vector silently falls back to slow deep copying! Marking move operations noexcept unlocks massive performance gains in standard library containers.

03The Canonical Rule of Five and Rule of Zero

The Rule of Five states: If a class requires a custom implementation of any one of the following special member functions, it almost certainly requires all five to manage its resources correctly:

1. Destructor (~T())

2. Copy Constructor (T(const T&))

3. Copy Assignment Operator (operator=(const T&))

4. Move Constructor (T(T&&) noexcept)

5. Move Assignment Operator (operator=(T&&) noexcept)

Conversely, the modern Rule of Zero states: Classes that do not directly manage raw resources should declare NONE of the special member functions. Instead, rely on modern RAII members (std::string, std::vector, std::unique_ptr) whose compiler-generated special members are automatically correct.

04Rule of Five Summary Reference

The five special member functions and their roles in modern C++ memory management:

Adhering to the Rule of Five or Rule of Zero completely eliminates memory leaks, double-free vulnerabilities, and unintended deep copies.

notes.txtPlain text
+-----------------------+-------------------------+-----------------------+| Special Member        | Syntax Signature        | Primary Action        |+-----------------------+-------------------------+-----------------------+| Destructor            | ~T() noexcept           | Release heap/handles  || Copy Constructor      | T(const T&)             | Allocate fresh deep cp|| Copy Assignment       | T& operator=(const T&)  | Copy-and-Swap / assign|| Move Constructor      | T(T&&) noexcept         | Steal ptrs, null source| Move Assignment       | T& operator=(T&&) noex  | Delete old, steal new |+-----------------------+-------------------------+-----------------------+
LET IT CLICK

The ideas worth keeping.

  • Move semantics transfers ownership of internal heap pointers in O(1) time via rvalue references.
  • Always mark move constructors and move assignment operators noexcept to enable vector optimization.
  • Follow the Rule of Five for manual resource managers and the Rule of Zero for high-level composite types.
TURN UNDERSTANDING INTO SOMETHING YOU CAN DO

Make it yours.

Type and test your code right here in the interactive workspace. Run your solution, check the output, and compare with the worked guide when ready.

01

Exercise 1: What does std move x actually do in compile

What does std::move(x) actually do in compiled machine code? Does it copy or move data by itself?

your_turn_1.cpp⚙️C++
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.
Explore a worked solution
one_possible_solution.cppC++
// std::move does NOT move or copy any data at runtime; it generates ZERO machine instructions.// It is purely a compile-time static_cast to an rvalue reference: static_cast<std::remove_reference_t<T>&&>(x).// It informs the compiler that 'x' can be treated as an expiring rvalue,// enabling overload resolution to select the move constructor or move assignment operator.

std::move is an unconditional cast to an rvalue reference.

02

Exercise 2: Explain what happens if a move constructor st

Explain what happens if a move constructor steals a pointer other.data_ but forgets to set other.data_ = nullptr;.

your_turn_2.cpp⚙️C++
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.
Explore a worked solution
one_possible_solution.cppC++
// If other.data_ is not set to nullptr, both this->data_ and other.data_ point to the same heap block.// When 'other' goes out of scope and its destructor executes, it will delete the memory!// The newly constructed object now holds a dangling pointer. When it later destructs,// a fatal double-free crash occurs.

Think about what the destructor of 'other' does when 'other' goes out of scope.

A SMALL QUESTION. A USEFUL NEXT STEP.

What stayed with you?

Check the ideas while they’re fresh. Your answers stay in this page and feedback appears as you go.

A LITTLE ACTIVE RECALL0 / 3 answered
01What is the primary operational advantage of a move constructor over a copy constructor?
02Why does std::vector fall back to slow copy constructors during reallocation if a class's move constructor lacks the noexcept specifier?
03What is the Rule of Zero in modern C++?
⚡CODING CHALLENGE
🔒Required to Mark Lesson Complete

Exercise 1: What does std move x actually do in compile

What does std::move(x) actually do in compiled machine code? Does it copy or move data by itself?

EXPECTED OUTPUT
Build completed. Binary executed.
[Exit code: 0]
main.cppC++
Ctrl + ↵
Execution Console
Click "Run & Verify" (or press Ctrl + Enter) to test your code against the challenge.

Keep exploring.

The official references behind this lesson, when you want a second angle or the full details.

One lesson closer.

Reading is a start. Trying it yourself makes the connection.

Solve the hands-on coding challenge in the knowledge section to verify your code and unlock lesson completion.