Move_semantics
Move Semantics and Rvalue References
Section titled “Move Semantics and Rvalue References”Move semantics is one of the most important features of modern C++. It enables efficient resource transfer without copying.
Lvalues and Rvalues
Section titled “Lvalues and Rvalues”int x = 10; // x is lvalue, 10 is rvalue
// Lvalue: has address, can appear on left of =// Rvalue: temporary, can only appear on right of =Rvalue References
Section titled “Rvalue References”int x = 10;int&& rref = 10; // Rvalue reference to temporary// int&& rref2 = x; // Error: can't bind rvalue ref to lvalue
// Lvalue referenceint& lref = x; // Lvalue reference to xMove Semantics
Section titled “Move Semantics”The Problem
Section titled “The Problem”std::vector<int> createVector() { std::vector<int> v = {1, 2, 3, 4, 5}; return v; // Returns by value - copies the vector!}Before C++11, returning a large container would copy it.
The Solution: Move Constructor
Section titled “The Solution: Move Constructor”class Buffer {private: int* data; size_t size;
public: Buffer(size_t s) : size(s) { data = new int[size]; }
// Copy constructor Buffer(const Buffer& other) : size(other.size) { data = new int[size]; std::copy(other.data, other.data + size, data); }
// Move constructor Buffer(Buffer&& other) noexcept : data(other.data), size(other.size) { other.data = nullptr; // Transfer ownership other.size = 0; }
~Buffer() { delete[] data; }};Using Move Semantics
Section titled “Using Move Semantics”Buffer createBuffer() { Buffer b(1000); return b; // Now moves instead of copies!}
int main() { Buffer b1(1000); Buffer b2(std::move(b1)); // Move constructor called
// b1 is now in valid but unspecified state}std::move
Section titled “std::move”std::move converts an lvalue to rvalue:
std::vector<int> v1 = {1, 2, 3};std::vector<int> v2 = std::move(v1); // Move, not copy
// v1 is now empty (valid but unspecified)When to Use std::move
Section titled “When to Use std::move”- Returning local objects
std::vector<int> getData() { std::vector<int> data = {1, 2, 3}; return data; // RVO or move}- Moving into containers
std::vector<std::vector<int>> vec;vec.push_back(std::move(myVector));- Moving members in constructors
class MyClass { std::vector<int> data;public: MyClass(std::vector<int> d) : data(std::move(d)) {}};Move Assignment
Section titled “Move Assignment”class Buffer { // ... (same members as before)
// Move assignment operator Buffer& operator=(Buffer&& other) noexcept { if (this != &other) { delete[] data; data = other.data; size = other.size; other.data = nullptr; other.size = 0; } return *this; }};
int main() { Buffer b1(100); Buffer b2(200); b2 = std::move(b1); // Move assignment}Rule of Five (C++11)
Section titled “Rule of Five (C++11)”If you define any of these, define all five:
class MyClass {private: int* data;
public: // 1. Destructor ~MyClass() { delete[] data; }
// 2. Copy constructor MyClass(const MyClass& other);
// 3. Copy assignment MyClass& operator=(const MyClass& other);
// 4. Move constructor MyClass(MyClass&& other) noexcept;
// 5. Move assignment MyClass& operator=(MyClass&& other) noexcept;};Complete Example
Section titled “Complete Example”#include <iostream>#include <vector>#include <string>
class BigObject {private: std::vector<int> data; std::string name;
public: BigObject(const std::string& n, size_t s) : name(n) { data.resize(s, 0); std::cout << "Constructing " << name << "\n"; }
// Copy constructor BigObject(const BigObject& other) : name(other.name + "_copy"), data(other.data) { std::cout << "Copying " << name << "\n"; }
// Move constructor BigObject(BigObject&& other) noexcept : name(std::move(other.name)), data(std::move(other.data)) { std::cout << "Moving " << name << "\n"; }
void print() const { std::cout << name << " with " << data.size() << " elements\n"; }};
int main() { std::cout << "=== Creating obj1 ===\n"; BigObject obj1("first", 1000);
std::cout << "\n=== Copying obj1 to obj2 ===\n"; BigObject obj2 = obj1; // Copy
std::cout << "\n=== Moving obj1 to obj3 ===\n"; BigObject obj3 = std::move(obj1); // Move
std::cout << "\n=== Vector operations ===\n"; std::vector<BigObject> vec; vec.push_back(BigObject("temp", 500));
std::cout << "\n=== End ===\n"; return 0;}Key Takeaways
Section titled “Key Takeaways”- Move semantics transfer ownership without copying
- Rvalue references (
&&) bind to temporaries std::moveconverts lvalue to rvalue- Move constructors transfer resources efficiently
- Follow the Rule of Five when managing resources
Next Steps
Section titled “Next Steps”Now let’s continue with more modern C++ features.
Next Chapter: 27_nullptr.md - nullptr and Modern Type Safety