CodeNebula
C++11coreintermediate

std::move (C++11 Addition)

C++11 · Modern Revolution · Compiler flag: -std=c++11

Explanation

Converts an lvalue to an rvalue, enabling move semantics.

Real-World Scenario

Transfer ownership of a resource in a resource manager.

Quick Snippet

snippet.cpp
#include <utility> std::vector<int> vec = std::move(otherVec);

Full Example

move.cpp
// CodeNebula - C++11 Example: std::move Casting Utility
// Compile: g++ -std=c++11 -Wall -Wextra -o example move.cpp

// Demonstrates std::move as a casting utility. std::move does NOT move
// anything -- it is an unconditional cast to an rvalue reference, signaling
// that the caller is done with the object and its resources may be taken.

#include <iostream>
#include <string>
#include <vector>
#include <utility>
#include <algorithm>

class Resource {
    std::string name_;
public:
    Resource(const std::string& n) : name_(n)
    {
        std::cout << "  [Ctor]  " << name_ << std::endl;
    }
    Resource(const Resource& o) : name_(o.name_)
    {
        std::cout << "  [Copy]  " << name_ << std::endl;
    }
    Resource(Resource&& o) noexcept : name_(std::move(o.name_))
    {
        std::cout << "  [Move]  " << name_ << std::endl;
    }
    Resource& operator=(Resource&& o) noexcept
    {
        name_ = std::move(o.name_);
        std::cout << "  [Move=] " << name_ << std::endl;
        return *this;
    }
    const std::string& name() const { return name_; }
};

int main()
{
    // ------------------------------------------------------------------
    // 1. std::move is just a cast (nothing moves yet)
    // ------------------------------------------------------------------
    std::cout << "=== std::move is a cast ===" << std::endl;
    std::string s = "Hello";
    std::string&& rref = std::move(s);  // cast only, no move yet
    std::cout << "  s after cast: \"" << s << "\" (still intact)" << std::endl;
    std::cout << "  rref:         \"" << rref << "\"" << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 2. Move happens when an rvalue ref is consumed
    // ------------------------------------------------------------------
    std::cout << "=== Actual move occurs on consumption ===" << std::endl;
    std::string dest = std::move(s);    // string move ctor consumes
    std::cout << "  dest: \"" << dest << "\"" << std::endl;
    std::cout << "  s:    \"" << s << "\" (moved-from)" << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 3. std::move with custom types
    // ------------------------------------------------------------------
    std::cout << "=== Move with Resource class ===" << std::endl;
    Resource r1("Database");
    Resource r2(std::move(r1));         // triggers move constructor
    std::cout << "  r2.name(): " << r2.name() << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 4. std::move into containers
    // ------------------------------------------------------------------
    std::cout << "=== Move into vector ===" << std::endl;
    std::vector<Resource> vec;
    vec.reserve(3);     // prevent reallocation

    Resource a("Alpha");
    Resource b("Beta");
    vec.push_back(a);              // copy (a is lvalue)
    vec.push_back(std::move(b));   // move (std::move casts to rvalue)

    std::cout << "  vec[0]: " << vec[0].name() << std::endl;
    std::cout << "  vec[1]: " << vec[1].name() << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 5. std::move in swap idiom
    // ------------------------------------------------------------------
    std::cout << "=== Move-based swap ===" << std::endl;
    std::string x = "Left";
    std::string y = "Right";
    std::cout << "  Before: x=\"" << x << "\", y=\"" << y << "\"" << std::endl;

    // Three moves, zero allocations
    std::string tmp = std::move(x);
    x = std::move(y);
    y = std::move(tmp);

    std::cout << "  After:  x=\"" << x << "\", y=\"" << y << "\"" << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 6. Moved-from objects are valid but unspecified
    // ------------------------------------------------------------------
    std::cout << "=== Moved-from state ===" << std::endl;
    std::vector<int> v = {1, 2, 3};
    std::vector<int> v2 = std::move(v);
    // v is valid: we can call clear, size, assign, etc.
    std::cout << "  v.size() after move : " << v.size() << std::endl;
    v.assign({10, 20});  // reuse is fine
    std::cout << "  v after reassign    : ";
    for (int n : v) std::cout << n << " ";
    std::cout << std::endl;

    return 0;
}

/*
Expected output:

=== std::move is a cast ===
  s after cast: "Hello" (still intact)
  rref:         "Hello"

=== Actual move occurs on consumption ===
  dest: "Hello"
  s:    "" (moved-from)

=== Move with Resource class ===
  [Ctor]  Database
  [Move]  Database
  r2.name(): Database

=== Move into vector ===
  [Ctor]  Alpha
  [Ctor]  Beta
  [Copy]  Alpha
  [Move]  Beta
  vec[0]: Alpha
  vec[1]: Beta

=== Move-based swap ===
  Before: x="Left", y="Right"
  After:  x="Right", y="Left"

=== Moved-from state ===
  v.size() after move : 0
  v after reassign    : 10 20
*/
Run command
g++ -std=c++11 -Wall -Wextra -o example move.cpp