Move Constructor in C++

A move constructor in C++ is a special constructor that transfers resources from one object to another instead of copying them. It became part of the language in C++11 and is one of the key reasons modern C++ can be both expressive and efficient. Instead of duplicating memory, file handles, buffers, or other expensive resources, a move constructor allows a new object to take ownership of those resources from a temporary or otherwise movable object.

This matters because copying can be expensive. If an object owns a large dynamic array, a string buffer, a container, or another heap-based resource, copying means allocating new storage and duplicating the contents. Sometimes that is necessary, but sometimes the source object is about to disappear anyway. In that situation, copying wastes time and memory. A move constructor solves that by reusing the existing resource instead of cloning it.

What Is a Move Constructor in C++?

A move constructor is a constructor that initializes a new object by transferring the state of another object, usually a temporary object or an object explicitly marked as movable. Unlike a copy constructor, which duplicates data, a move constructor usually steals internal resources and leaves the source object in a valid but unspecified moved-from state.

ClassName(ClassName&& other);

The && here is the key. It means the parameter is an rvalue reference, which is the language mechanism C++ uses to identify objects whose resources can be transferred.

A move constructor in C++ creates a new object by transferring ownership of resources from another object instead of copying them.

Why Move Constructor Was Introduced

Before C++11, classes often had to rely only on copying. That meant temporary objects, return values, and large resource-owning objects could trigger unnecessary allocations and data duplication. As software grew larger and performance requirements became stricter, this limitation became expensive.

  • Copying large objects can be slow.
  • Copying may require extra heap allocation.
  • Temporary objects often do not need to keep their data after use.
  • Resource ownership should sometimes be transferred, not duplicated.

Move semantics gave C++ a direct way to express transfer of ownership. This is one of the major language improvements that made modern C++ practical for high-performance applications without giving up abstraction.

Syntax of Move Constructor in C++

The normal syntax of a move constructor uses an rvalue reference to the same class type.

class Box
{
public:
    Box(Box&& other)
    {
        // transfer resources from other
    }
};

The source object is usually not copied. Instead, its internal pointers, handles, or buffers are transferred into the new object, and the source is reset to a safe state.

What Is an Rvalue in C++?

To understand move constructors properly, you need a basic idea of rvalues. An rvalue is generally a temporary value or an object that is about to go away. Because it does not need to preserve its original state for future use in the same way as a normal named object, it is a good candidate for resource transfer.

A move constructor accepts an rvalue reference because the language assumes that such an object can safely give up its internals. That is why move semantics are tied directly to &&.

Basic Example of Move Constructor

#include <iostream>
using namespace std;

class Sample
{
public:
    int* data;

    Sample(int value)
    {
        data = new int(value);
    }

    Sample(Sample&& other)
    {
        data = other.data;
        other.data = nullptr;
        cout << "Move constructor called" << endl;
    }

    ~Sample()
    {
        delete data;
    }
};

int main()
{
    Sample s1(50);
    Sample s2 = std::move(s1);
}

Here the pointer is not duplicated. The ownership of the allocated integer is transferred from s1 to s2. Then s1.data is set to nullptr so that both objects do not try to delete the same memory.

When the Move Constructor Is Called

A move constructor can be called in several situations where the compiler sees an rvalue or where you explicitly convert an object into an rvalue with std::move.

  • When an object is initialized from a temporary object.
  • When an object is initialized from a function return value in cases where move is selected.
  • When std::move is used on an existing object.
  • When containers relocate elements and use move operations for efficiency.

In practice, compilers may also apply copy elision or return value optimization, so the move constructor is not always visibly called even when move semantics are conceptually involved. That is an optimization benefit, not a contradiction.

Move Constructor vs Copy Constructor

Both constructors create a new object from another object, but they do not do the same kind of work.

FeatureCopy ConstructorMove Constructor
GoalDuplicate the source objectTransfer resources from the source object
Parameter typeconst ClassName&ClassName&&
Source object after operationRemains unchangedUsually left valid but moved-from
PerformanceCan be expensiveOften cheaper for resource-owning classes

The move constructor does not replace the copy constructor completely. Some classes still need both. Copying and moving represent different semantics, and good class design handles each intentionally.

What std::move Does

std::move does not move anything by itself. That is a common misconception. It simply casts its argument into an rvalue expression, which tells the compiler that the object may be moved from. The actual transfer happens only if the class provides move operations or if the selected operation uses move semantics.

Sample s1(100);
Sample s2 = std::move(s1);

After this call, s1 should still remain valid, but you should not assume it still contains the original useful data unless the class specifically documents that guarantee.

Moved-From Objects in C++

A moved-from object must remain valid, meaning it can be safely destroyed and assigned a new value. But its exact content is often unspecified. That is an important design principle. After moving from an object, you should not keep using its old state as if nothing happened.

For simple teaching examples, developers often set raw pointers to nullptr inside the move constructor. In real-world code, the moved-from state should be safe, minimal, and clearly documented when the class has nontrivial behavior.

Compiler-Generated Move Constructor

If you do not write a move constructor, the compiler may generate one automatically, but only under certain conditions. If the class has members whose move behavior is valid and no rule prevents generation, the compiler can produce a default move constructor that performs member-wise moving.

However, once you start defining special member functions manually, generation rules become more complicated. That is why understanding the Rule of Five is important when designing resource-owning classes.

Defaulted and Deleted Move Constructor

Modern C++ lets you explicitly request or disable move behavior. If member-wise moving is correct, you can write = default. If moving should not be allowed, you can write = delete.

class Buffer
{
public:
    Buffer(Buffer&&) = default;
};
class Device
{
public:
    Device(Device&&) = delete;
};

This makes the class contract explicit and prevents accidental behavior that does not match the ownership model of the type.

Move Constructor and the Rule of Five

In modern C++, if a class manages resources manually, the special member functions often need to be considered together. These are destructor, copy constructor, copy assignment operator, move constructor, and move assignment operator. This idea is known as the Rule of Five.

The reason is consistency. If you implement moving but forget about copying or assignment, the class may behave correctly in one context and dangerously in another. Resource-owning classes should define a coherent lifetime policy instead of treating each special function as an isolated feature.

Why noexcept Matters for Move Constructor

In many standard library containers, move operations become more useful when they are marked noexcept. If a move constructor can throw exceptions, a container such as std::vector may choose copying in some operations to preserve strong exception safety guarantees. That means a move constructor that is conceptually correct may still be underused unless it is also safe enough to be declared non-throwing.

class Buffer
{
public:
    Buffer(Buffer&& other) noexcept
    {
        // transfer resources safely
    }
};

This is a practical performance detail that becomes important in well-optimized C++ code.

Common Mistakes with Move Constructors

  • Using std::move and then continuing to rely on the old object state as if nothing changed.
  • Forgetting to reset raw pointers or handles in the moved-from object.
  • Writing a move constructor that still performs deep copying, which defeats the performance purpose.
  • Implementing move operations without considering copy operations and destructor behavior together.
  • Assuming std::move performs a move even when the type has no move support.

These mistakes usually come from treating move semantics as syntax instead of ownership design. The syntax is only the mechanism. The real topic is safe and efficient resource transfer.

Best Practices for Move Constructors in C++

  • Use move constructors for classes that own transferable resources.
  • Leave the moved-from object in a valid and safely destructible state.
  • Prefer noexcept when the move operation truly cannot fail.
  • Use = default when member-wise moving is correct and sufficient.
  • Think in terms of ownership rules, not only syntax rules.

These practices help the class cooperate correctly with the language, the standard library, and other developers who will read or use the type later.

Move Constructor in Return Values and Containers

Move constructors matter a lot in real C++ code because objects are frequently returned from functions and relocated inside standard containers. Even though modern compilers often remove temporary copies through optimization, move support still provides a safe and efficient fallback when direct construction is not possible. Containers such as std::vector also benefit from movable element types because reallocation can transfer elements more cheaply than deep-copying each one.

Important Rules to Remember About Move Constructor

  • A move constructor transfers resources from one object to another.
  • Its common syntax is ClassName(ClassName&& other).
  • It usually works with rvalues and objects passed through std::move.
  • A moved-from object must remain valid, even if its content is unspecified.
  • Move constructors are central to modern C++ performance and ownership design.

Continue learning C++ in order
Follow the topic sequence with the previous and next lesson.