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
- What is a forwarding reference and how does it differ from an rvalue reference?
- Why mark move operations noexcept?
Show answers
- A forwarding reference is a template parameter of form T&& with type deduction; it binds to lvalues and rvalues, unlike a plain rvalue reference.
- It enables containers to move elements during reallocation without falling back to copies if exceptions might be thrown.
Exercises
- Implement a small vector-like wrapper that supports move-only elements and verify moves occur (e.g., count moves).
- Write a make_unique-like function using perfect forwarding.