C++ Foundations·Modern C++ without the folklore

Move semantics

Move transfers resources instead of copying them, which is cheaper for expiring values.

Intermediate 13 min read Lesson 2 of 300 Challenge included
What you will be able to do
  • Move transfers resources instead of copying them, avoiding deep copies.
  • std::move is a cast to an rvalue; the actual moving happens in a move constructor or move assignment.
  • Provide move operations for types that own expensive resources.
  • After moving from an object, treat it as valid but unknown and do not rely on its contents.

In plain English

A move transfers the resources of one object into another instead of copying them, which is cheaper when the source is about to be discarded. An rvalue is a temporary or expiring value, such as the result of an expression that is not stored in a variable. Calling std::move does not move anything itself; it casts a value to an rvalue so a move constructor or move assignment can run. A move constructor and a move assignment operator steal the internal data and leave the source in a valid but unspecified state, so you should not rely on the source again afterwards.

Step by step

  1. 1Write a class that owns a resource such as a std::vector or std::string.
  2. 2Add a move constructor that transfers the resource from another instance.
  3. 3Add a move assignment operator that transfers into an existing object.
  4. 4Mark both move operations noexcept so containers can use them safely.
  5. 5Use std::move when handing an expiring value into a move-capable target.
buffer.cppC++
#include <cstddef>
#include <iostream>
#include <utility>
#include <vector>

class Buffer {
public:
    explicit Buffer(std::vector<int> data) : data_(std::move(data)) {}

    Buffer(Buffer&& other) noexcept : data_(std::move(other.data_)) {}

    Buffer& operator=(Buffer&& other) noexcept {
        data_ = std::move(other.data_);
        return *this;
    }

    std::size_t size() const { return data_.size(); }

private:
    std::vector<int> data_;
};

Buffer make_buffer() {
    std::vector<int> values{1, 2, 3, 4};
    return Buffer{std::move(values)};
}

int main() {
    Buffer a = make_buffer();
    Buffer b = std::move(a);
    std::cout << b.size() << "\n";
}

Common mistakes

  • Calling std::move and expecting data to move when the type has no move constructor results in a plain copy instead.
  • Using an object after it has been moved from is dangerous because its contents are unspecified.
  • Leaving the source object in a state that violates its class invariants breaks later code that touches it.
  • Forgetting noexcept on move operations can make standard containers fall back to copying for exception safety.
Your turn

Move a vector

Medium

Write a class Holder that stores a std::vector<int>, with a move constructor and a move assignment operator that move the vector from the source. Mark both noexcept.

CPP · starter
class Holder {
public:
    explicit Holder(std::vector<int> data) : data_(std::move(data)) {}
private:
    std::vector<int> data_;
};
Check your understanding before moving on.
Knowledge checkQuestion 1

What does std::move actually do?

Select an answer to continue
Study tools

Make it yours.

Keep a private note for this lesson, then turn the key ideas into flashcards you can revisit.

Sign in to save notes and flashcards.Both are private to your account and stay with your progress.
Sign in
Finished reading?

Lock in what you just learned.

Mark this lesson complete to save your place and move one step closer to the certificate.

Lesson 2 of 300 · 0% of course