CodeNebula
C++11coreintermediate

Move Constructor (C++11 Addition)

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

Explanation

A constructor that transfers resources from a temporary object rather than copying them, enabling efficient object creation from rvalues.

Real-World Scenario

Construct a large image buffer by stealing the data from a temporary returned by a factory function, avoiding an expensive deep copy.

Quick Snippet

snippet.cpp
class Buffer {
    int* data;
    size_t size;
public:
    Buffer(Buffer&& other) noexcept
        : data(other.data), size(other.size) {
        other.data = nullptr;
        other.size = 0;
    }
};

Full Example

move_constructor.cpp
// CodeNebula - C++11 Example: Move Constructor Implementation
// Compile: g++ -std=c++11 -Wall -Wextra -o example move_constructor.cpp

// Demonstrates how to implement a move constructor. The move constructor
// transfers ownership of resources from a temporary (rvalue) object,
// leaving the source in a valid but empty state. Essential for the Rule of Five.

#include <iostream>
#include <cstring>
#include <utility>
#include <algorithm>

// Real-world scenario: a string class that manages its own memory
class MyString {
    char* data_;
    std::size_t length_;

public:
    // Regular constructor
    MyString(const char* str = "")
        : data_(new char[std::strlen(str) + 1]), length_(std::strlen(str))
    {
        std::strcpy(data_, str);
        std::cout << "  [Ctor]  \"" << data_ << "\"" << std::endl;
    }

    // Copy constructor (deep copy)
    MyString(const MyString& other)
        : data_(new char[other.length_ + 1]), length_(other.length_)
    {
        std::strcpy(data_, other.data_);
        std::cout << "  [Copy]  \"" << data_ << "\"" << std::endl;
    }

    // Move constructor (resource theft - no allocation!)
    MyString(MyString&& other) noexcept
        : data_(other.data_),        // steal the pointer
          length_(other.length_)     // steal the length
    {
        // Leave source in valid empty state
        other.data_ = nullptr;
        other.length_ = 0;
        std::cout << "  [Move]  \"" << data_ << "\"" << std::endl;
    }

    // Copy assignment
    MyString& operator=(const MyString& other)
    {
        if (this != &other) {
            delete[] data_;
            length_ = other.length_;
            data_ = new char[length_ + 1];
            std::strcpy(data_, other.data_);
            std::cout << "  [Copy=] \"" << data_ << "\"" << std::endl;
        }
        return *this;
    }

    // Move assignment
    MyString& operator=(MyString&& other) noexcept
    {
        if (this != &other) {
            delete[] data_;
            data_ = other.data_;
            length_ = other.length_;
            other.data_ = nullptr;
            other.length_ = 0;
            std::cout << "  [Move=] \"" << data_ << "\"" << std::endl;
        }
        return *this;
    }

    // Destructor
    ~MyString()
    {
        std::cout << "  [Dtor]  " << (data_ ? data_ : "(null)") << std::endl;
        delete[] data_;
    }

    const char* c_str() const { return data_ ? data_ : ""; }
    std::size_t length() const { return length_; }
};

// Factory function: return value triggers move
MyString createGreeting(const char* name)
{
    MyString s(name);
    return s;
}

int main()
{
    // ------------------------------------------------------------------
    // 1. Move constructor via std::move
    // ------------------------------------------------------------------
    std::cout << "=== Direct move construction ===" << std::endl;
    MyString a("Hello");
    MyString b(std::move(a));   // move constructor
    std::cout << "  b = \"" << b.c_str() << "\"" << std::endl;
    std::cout << "  a = \"" << a.c_str() << "\" (moved-from)" << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 2. Move constructor from temporary
    // ------------------------------------------------------------------
    std::cout << "=== Move from temporary ===" << std::endl;
    MyString c(MyString("Temporary"));  // may be elided by compiler
    std::cout << "  c = \"" << c.c_str() << "\"" << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 3. Move constructor from factory function
    // ------------------------------------------------------------------
    std::cout << "=== Factory return ===" << std::endl;
    MyString d = createGreeting("World");
    std::cout << "  d = \"" << d.c_str() << "\"" << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 4. Swap using moves (three moves, zero allocations)
    // ------------------------------------------------------------------
    std::cout << "=== Move-based swap ===" << std::endl;
    MyString x("First");
    MyString y("Second");
    std::cout << "  Before: x=\"" << x.c_str() << "\", y=\"" << y.c_str() << "\"" << std::endl;

    MyString temp(std::move(x));
    x = std::move(y);
    y = std::move(temp);
    std::cout << "  After:  x=\"" << x.c_str() << "\", y=\"" << y.c_str() << "\"" << std::endl;

    std::cout << std::endl << "=== Cleanup ===" << std::endl;
    return 0;
}

/*
Expected output (some moves may be elided by NRVO):

=== Direct move construction ===
  [Ctor]  "Hello"
  [Move]  "Hello"
  b = "Hello"
  a = "" (moved-from)

=== Move from temporary ===
  [Ctor]  "Temporary"
  c = "Temporary"

=== Factory return ===
  [Ctor]  "World"
  d = "World"

=== Move-based swap ===
  [Ctor]  "First"
  [Ctor]  "Second"
  Before: x="First", y="Second"
  [Move]  "First"
  [Move=] "Second"
  [Move=] "First"
  After:  x="Second", y="First"

=== Cleanup ===
  [Dtor]  (null)
  [Dtor]  First
  [Dtor]  Second
  [Dtor]  World
  [Dtor]  (null)
  [Dtor]  Hello
*/
Run command
g++ -std=c++11 -Wall -Wextra -o example move_constructor.cpp