C++ - Move Semantics & Perfect Forwarding

Overview

Estimated time: 70–90 minutes

Write efficient code by moving instead of copying. Learn move constructors/assignments and perfect forwarding patterns with forwarding references.

Learning Objectives

  • Implement move constructor and move assignment safely.
  • Use std::move correctly and understand moved-from states.
  • Forward callables and arguments perfectly with template forwarding references.

Prerequisites

Move constructor and assignment

#include <utility>
#include <string>
#include <iostream>
struct S {
  std::string data;
  S() = default;
  S(std::string d): data(std::move(d)) {}
  S(S&& other) noexcept : data(std::move(other.data)) {}
  S& operator=(S&& other) noexcept {
    if (this != &other) data = std::move(other.data);
    return *this;
  }
};
int main(){ S a{"hello"}; S b = std::move(a); std::cout << b.data << "\n"; }

Perfect forwarding

#include <utility>
#include <iostream>

void g(int&){ std::cout << "lvalue\n"; }
void g(int&&){ std::cout << "rvalue\n"; }

template <class T>
void f(T&& x){ g(std::forward<T>(x)); }

int main(){ int a=0; f(a); f(1); }

Expected Output: lvalue rvalue

Beginner Boosters

#include <vector>
#include <string>
#include <iostream>
int main(){
  std::vector<std::string> v;
  std::string s = "abc";
  v.push_back(s);              // copies
  v.push_back(std::move(s));   // moves
  std::cout << v[0] << "," << v[1] << "\n"; // abc,abc
}

Common Pitfalls

  • Using an object after it has been moved from without reassigning it (it is valid but unspecified).
  • Forgetting noexcept on move operations can inhibit optimizations in containers.

Checks for Understanding

  1. What is a forwarding reference and how does it differ from an rvalue reference?
  2. Why mark move operations noexcept?
Show answers
  1. A forwarding reference is a template parameter of form T&& with type deduction; it binds to lvalues and rvalues, unlike a plain rvalue reference.
  2. It enables containers to move elements during reallocation without falling back to copies if exceptions might be thrown.

Exercises

  1. Implement a small vector-like wrapper that supports move-only elements and verify moves occur (e.g., count moves).
  2. Write a make_unique-like function using perfect forwarding.