Move Constructors in C++

Last Updated : 4 Jul, 2026

A move constructor is a special constructor that transfers the ownership of resources (such as dynamically allocated memory, file handles, or sockets) from one object to another instead of copying them.

  • Improves performance by avoiding unnecessary deep copies.
  • Mainly used with temporary objects (rvalues).
C++
#include <iostream>
using namespace std;

class Geeks {
private:
    int* ptr;

public:
    // Constructor
    Geeks(int value) {
        // Dynamically allocate memory
        ptr = new int(value); 
        cout << "Constructor called\n";
    }

    // Move Constructor
    Geeks(Geeks&& obj) {
        cout << "Move Constructor called\n";
        // Steal the pointer
        ptr = obj.ptr;        
        obj.ptr = nullptr;    
    }

    // Destructor
    ~Geeks() {
        if (ptr != nullptr) {
            cout << "Destructor deleting data: " << *ptr << endl;
        } else {
            cout << "Destructor called on nullptr\n";
        }
        delete ptr;
    }

    // Display function
    void display() {
        if (ptr)
            cout << "Value: " << *ptr << endl;
        else
            cout << "No data\n";
    }
};

int main() {
    // Constructor is called
    Geeks obj1(42);              
    // Move constructor is called
    Geeks obj2 = std::move(obj1); 

    cout << "\nAfter move:\n";
    cout << "obj1: ";
    // Should show "No data"
    obj1.display();              
    cout << "obj2: ";
    // Should show "Value: 42"
    obj2.display();              

    return 0;
}

Output
Constructor called
Move Constructor called

After move:
obj1: No data
obj2: Value: 42
Destructor deleting data: 42
Destructor called on nullptr

Syntax

ClassName(ClassName&& other);

Where,

  • ClassName&& is an rvalue reference.
  • other is the temporary object whose resources are transferred.
  • The source object is usually left in a valid but empty state (commonly by setting pointers to nullptr).

Situations Where Move Constructors Are Invoked

A move constructor is typically invoked in the following situations:

  • Returning an object by value.
  • Initializing an object from a temporary object.
  • Using std::move() on an existing object.
  • During container reallocations (for example, std::vector) when move operations are available.

Example:

MyClass obj2 = std::move(obj1);

Move Constructor in STL Containers

STL containers frequently relocate their elements while resizing. A move constructor significantly reduces the overhead of these operations.

Without Move Constructor

When a move constructor is not available, the compiler uses the copy constructor during container reallocation.

  • Every element is copied.
  • Deep copies are performed repeatedly.
  • More constructor and destructor calls occur.
  • Results in lower performance.
C++
#include <iostream>
#include <vector>
using namespace std;

// Move Class
class Move {
private:
    // Declaring the raw pointer as
    // the data member of the class
    int* data;

public:
    // Constructor
    Move(int d)
    {
        // Declare object in the heap
        data = new int;
        *data = d;

        cout << "Constructor is called for " << d << endl;
    };

    // Copy Constructor to delegated
    // Copy constructor
    Move(const Move& source)
        : Move{ *source.data }
    {

        // Copying constructor copying
        // the data by making deep copy
        cout << "Copy Constructor is called - "
             << "Deep copy for " << *source.data << endl;
    }

    // Destructor
    ~Move()
    {
        if (data != nullptr)

            // If the pointer is not
            // pointing to nullptr
            cout << "Destructor is called for " << *data
                 << endl;
        else

            // If the pointer is
            // pointing to nullptr
            cout << "Destructor is called"
                 << " for nullptr" << endl;

        // Free the memory assigned to
        // data member of the object
        delete data;
    }
};

// Driver Code
int main()
{
    // Create vector of Move Class
    vector<Move> vec;

    // Inserting object of Move class
    vec.push_back(Move{ 10 });
    vec.push_back(Move{ 20 });
    return 0;
}

Output
Constructor is called for 10
Constructor is called for 10
Copy Constructor is called - Deep copy for 10
Destructor is called for 10
Constructor is called for 20
Constructor is called for 20
Copy Constructor is called - Deep copy for 20
Constructor is called for 10
Copy Constructor is called - Deep copy for 10
Destructor is called for 10
Destructor is called for 20
Destructor is called for 10
Destructor is called for 20

Explanation

  • Since the class provides only a copy constructor, existing elements are deep-copied whenever the vector grows.
  • These additional copy operations increase the overall execution time.

With Move Constructor

Adding a move constructor allows the container to transfer resources instead of copying them.

  • Existing resources are reused.
  • Fewer deep copies are required.
  • Performance improves significantly.
  • Temporary objects become inexpensive to relocate.
C++
#include <iostream>
#include <vector>
using namespace std;

// Move Class
class Move {
private:
    // Declare the raw pointer as
    // the data member of class
    int* data;

public:
    // Constructor
    Move(int d)
    {
        // Declare object in the heap
        data = new int;
        *data = d;
        cout << "Constructor is called for " << d << endl;
    };

    // Copy Constructor
    Move(const Move& source)
        : Move{ *source.data }
    {

        // Copying the data by making
        // deep copy
        cout << "Copy Constructor is called -"
             << "Deep copy for " << *source.data << endl;
    }

    // Move Constructor
    Move(Move&& source)
        : data{ source.data }
    {

        cout << "Move Constructor for " << *source.data
             << endl;
        source.data = nullptr;
    }

    // Destructor
    ~Move()
    {
        if (data != nullptr)

            // If pointer is not pointing
            // to nullptr
            cout << "Destructor is called for " << *data
                 << endl;
        else

            // If pointer is pointing
            // to nullptr
            cout << "Destructor is called"
                 << " for nullptr " << endl;

        // Free up the memory assigned to
        // The data member of the object
        delete data;
    }
};

// Driver Code
int main()
{
    // Vector of Move Class
    vector<Move> vec;

    // Inserting Object of Move Class
    vec.push_back(Move{ 10 });
    vec.push_back(Move{ 20 });
    return 0;
}

Output
Constructor is called for 10
Move Constructor for 10
Destructor is called for nullptr 
Constructor is called for 20
Move Constructor for 20
Constructor is called for 10
Copy Constructor is called -Deep copy for 10
Destructor is called for 10
Destructor is called for nullptr 
Destructor is called for 10
Destructor is called for 20

Explanation

  • Temporary objects are moved instead of copied, and ownership of dynamically allocated memory is transferred.
  • No additional memory allocation is required, which improves performance by avoiding expensive deep-copy operations.

Note: During vector reallocation, some copy constructor calls may still occur if move operations are not guaranteed to be safe. This is where noexcept becomes important.

noexcept Move Constructor

A move constructor can be marked with the noexcept specifier to indicate that it will never throw an exception.

  • Guarantees that moving objects is exception-safe.
  • Allows STL containers to use move operations more aggressively.
  • Improves container performance during resizing.

Without noexcept

If a move constructor is not marked noexcept, STL containers may prefer copying objects to ensure exception safety.

C++
#include <bits/stdc++.h>
using namespace std;

class A {
public:
    A() {}
  
    // Move constructor not marked as noexcept
    A(A&& other) {
        cout << "Move constructor" << endl;
    }

    // Copy constructor
    A(const A& other) {
        cout << "Copy constructor" << endl;
    }
};

int main() {
    vector<A> v;

  	// Reserve space for at least two elements to
	// avoid immediate resizing
    v.reserve(2);

    // Uses the move constructor for the temporary objects
    v.push_back(A());
    v.push_back(A());

  	cout << "Resize happens" << endl;
    
    // Move constructor may be called again if resizing occurs
    v.push_back(A());
    
    return 0;
}

Output
Move constructor
Move constructor
Resize happens
Move constructor
Copy constructor
Copy constructor

Explanation: Since the move constructor is not marked noexcept, std::vector cannot guarantee exception safety during reallocation and therefore prefers copying existing elements instead of moving them.

With noexcept

Marking the move constructor as noexcept enables the STL to move existing elements during reallocation.

C++
#include <vector>
#include <iostream>
using namespace std;

class Test {
public:
    Test(){}
      
    // Move constructor marked as noexcept
    Test(Test&& other) noexcept {
        cout << "Move constructor  " << endl;
    }

    // Copy constructor
    Test(const Test& other) {
        cout << "Copy constructor  " << endl;
    }
};

int main() {
    vector<Test> vec;

    vec.reserve(2);  // Reserve space for at least two elements

  Test a;

    vec.push_back(Test());
    vec.push_back(Test());  // Uses the move constructor

    cout << "Resize happens" << endl;
    vec.push_back(Test());
    
    return 0;
}

Output
Move constructor  
Move constructor  
Resize happens
Move constructor  
Move constructor  
Move constructor  

Explanation: Since the move constructor is declared noexcept, std::vector can safely move elements instead of copying them during reallocation, making the operation more efficient.

Benefits of Using noexcept

Marking a move constructor as noexcept enables safer and more efficient optimizations.

  • Allows STL containers to move elements during reallocation.
  • Reduces unnecessary copy operations.
  • Enables better compiler optimizations.
  • Recommended for move constructors that cannot throw exceptions.

Copy Constructor vs Move Constructor

FeatureCopy ConstructorMove Constructor
PurposeCreates a copy of an object's resourcesTransfers ownership of resources
Parameterconst ClassName&ClassName&&
Resource HandlingDuplicates resourcesTransfers resources
Memory AllocationUsually allocates new memoryNo new allocation in most cases
PerformanceSlowerFaster
Source ObjectRemains unchangedLeft in a valid but unspecified state (commonly nullptr)
IntroducedC++98C++11change

Advantages of Move Constructors

Move constructors improve performance by transferring ownership of resources instead of copying them.

  • Avoid expensive deep-copy operations.
  • Reduce unnecessary memory allocations.
  • Improve the performance of STL containers during reallocation.
  • Efficiently manage dynamic resources such as memory and file handles.
Comment