C++ PROGRAMMING ยท 14 MIN STUDY

Copying, moving, and the Rule of Zero

Understand copy and move operations, ownership transfer, and modern class resource management.

Learning objectives

  • Distinguish copying from moving.
  • Recognize lvalues and rvalues at an introductory level.
  • Understand std::move as a cast that enables moving.
  • Apply the Rule of Zero and know when special member functions matter.

Prerequisites: classes, constructors/destructors, references, pointers, and std::vector. You should understand object lifetime before studying ownership transfer.

Copying makes another value

Copying creates a new object with a value based on an existing object. For a vector, copying normally creates another vector with its own elements. The two vectors can then be changed independently.

Moving can transfer resources

Moving allows a type to transfer resources from an object that is no longer needed. Standard containers and strings support efficient move operations. A moved-from standard-library object remains valid but its value is generally unspecified; you may destroy it or assign a new value to it, but do not assume its old contents remain.

C++17
#include <string>
#include <utility>

std::string original{"a long message"};
std::string destination = std::move(original);
// destination now owns the transferred value
// original is valid but its value is unspecified

std::move does not move anything by itself. It produces an rvalue reference expression that allows overload resolution to select a move operation when one is available.

Rule of Zero

The Rule of Zero recommends designing classes so their members manage resources themselves. If a class contains a std::string, std::vector, and std::unique_ptr, their constructors, assignment operators, and destructors already handle those resources. The class often needs no custom copy/move/destructor code.

Rule of Three and Rule of Five

If a class directly manages a resource and needs a custom destructor, copy constructor, or copy assignment operator, the Rule of Three says to consider all three. In modern C++, move constructor and move assignment may also be needed, giving the Rule of Five. These rules are warning signs that manual resource management may be avoidable through RAII members.

Common mistakes

  • Thinking std::move itself transfers memory.
  • Reading a moved-from object's value as if it were unchanged.
  • Writing custom copy/move functions for a class that could use standard RAII members.
  • Moving from an object and then using its old data without reinitializing it.

Practice

  1. Copy a vector and show that changing one copy does not change the other.
  2. Move a string into another string and explain the valid-but-unspecified state of the source.
  3. Explain why std::move is a cast, not a function that physically moves bytes.
  4. Design a class with vector and string members and explain why Rule of Zero applies.

Practice solutions

Show worked solutions
  1. #include <vector>
    std::vector<int> original{1, 2, 3};
    auto copy = original;
    copy[0] = 99;
    // original[0] is still 1
    Copying creates a separate vector with its own elements.
  2. #include <string>
    #include <utility>
    std::string source{"OpenLearn"};
    std::string destination = std::move(source);
    // destination owns the transferred value
    source.clear(); // valid operation on the moved-from string
    The source remains valid but its value is unspecified; do not assume it is empty.
  3. std::move is a cast that produces an xvalue expression. That can make a move constructor or move assignment operator eligible. The selected operation decides what resources are transferred; std::move itself moves no bytes.
  4. A class containing std::vector and std::string members can usually use compiler-generated copy, move, and destructor operations. Those member types already manage their own resources, so a custom destructor is unnecessary (Rule of Zero).

Check your understanding

Question: Does std::move guarantee that a move constructor runs?

Answer: No. It enables an rvalue-reference overload to be selected, but the type may not have a move operation and overload resolution still determines what happens.

Summary

Copying creates an independent value; moving can transfer resources. std::move enables move-aware overloads but does not perform a move on its own. Prefer Rule of Zero designs built from RAII members.

References