Move Semantics in C++11

Move semantics is one of the most exciting new features offered by C++11 standard and is complex enough to confuse many programmers. I think it is an extremely important concept that every C++ programmer should understand correctly in order to write modern and efficient C++ code. Hopefully this article will serve that purpose.

One of the major design principles that the C++ standard committee had when designing C++11 was to avoid unnecessary creating and copying of temporary objects, thereby achieving efficiency. Consider the below sample code snippet.

template <typename T>
void swap(T& param1, T& param2)
    const T temp = param1;
    param1 = param2;
    param2 = temp;

The above code is a simple template based function which swaps the values of it input parameters. It does so by creating a temporary object and copying over the value of param1 into a temporary variable and replacing param1 with value of param2. Then it achieves the final swap by copying the value of the temporary variable (which contains the original param1 value) back to param2. This is how most of the traditional C++98/03 swap functions were written. It is important to note that every time we copy a value from one variable to another for non-intrinsic types, its copy constructor is invoked. Even if you have not written an explicit copy constructor, the C++ compiler provides you one, for free when you compile your program. It seems that it would have been better if we had avoided copying the temporary object into param2 and moved it instead, since we know that the temporary variable is anyways going to be discarded. Move semantics will let you do this optimization.

As an another example, in general, whenever you return an object from a function “by-value”, the compiler will first copy the object being returned from the function into a temporary object and then again copy it from the temporary object to the target variable if specified. Usually the compiler will optimize this behavior by avoiding the extra copying which is called as “return value optimization” aka RVO. You will have to turn off this optimization in order to see this concept in action. This can be achieved by passing fno-elide-constructors command line flag to the gcc compiler. Consider the below code snippet.

#include <string> 
#include <iostream> 

struct Person
    int age_;
    std::string name_;

        std::cout << "Person - Constructor \n";

    Person(const Person&)
        std::cout << "Person - Copy constructor \n";

        std::cout << "Person - Destructor \n";

Person foo()
    return Person();

int main()
    std::cout << "Demonstrate the behaviour of usage of temporary objects \n";
    Person bob = foo();
    return 0;

To compile and execute the program using gcc compiler execute the below commands assuming the c++ source file is saved with the filename “”

g++ -fno-elide-constructors -std=c++11

Demonstrate the behavior of usage of temporary objects
Person – Constructor
Person – Copy constructor
Person – Copy constructor
Person – Destructor
Person – Destructor

In the above snippet the entry point function “main”, calls function “foo” where an object of class Person is created by invoking the constructor. While returning from “foo”, the Person object which was created in it, is copied to a temporary object by invoking the copy constructor and later again copied to object bob using the copy constructor. This seems, unnecessary copying of the same object twice. Can this be avoided? Certainly, yes and move semantics provided by C++11 would avoid this unnecessary copying of object.

The motivation of move semantics is to avoid unnecessary copying of objects by moving them. In the above case, the Person object created in function “foo” can be moved to variable “bob” instead of creating a temporary object and copying over to it before finally copying it to “bob”. In this particular case, probably, it does not matter if you move or copy the object since it does not contain a lot of data, but the performance gains would be significant if the object being moved is huge and is not trivial to copy the object. What if the object that needs to be moved contains hundred thousand records or a high resolution image captured from a satellite represented using a matrix of size billion? The cost to be copied can be measured in terms of CPU cycles, memory usage or the overall throughput of the program.

Logically speaking the concept of moving an object instead of copying in not new. Consider going to a painting exhibition and buying an authentic painting. The artist moves the piece of art from his exhibition and hands it over to you and does not create a photocopy to handover to you. You won’t be really happy if the artist did that, since you are paying for the genuine authentic painting and not a photocopy. Comparing it to a computer program, the artist avoided a lot of work by not making an exact copy again from scratch or making a photocopy, thereby achieving efficiency.

It would be ideal if the compiler would figure out, when it would make sense to move an object instead of copying them, which is does in most of the cases. Hence even if you recompile your old C++ 98/ 03 code using a new compiler supporting C++11 standard you should see a significant performance improvement in the execution time, especially if your code is making heavy use of standard template library (STL) since all STL containers and algorithms are move enabled/ optimized. We will discuss ahead, on how you can make your own code move enabled. As usual, the C++ language also hands over the necessary tools to the programmer in-case they want to explicitly move an object. It is important point worth mentioning that the compiler or the programmer himself should only be moving objects that would no longer be needed. In other words, only temporary objects should be moved which would not be used later. How does the compiler identify such objects? Let’s talk a bit about lvalues, rvalues, lvalue reference and rvalue reference.

Lvalues and Rvalues

The meaning of lvalue and rvalue is pretty much self-explanatory. An lvalue is something that appears on the left hand side of an expression while an rvalue appears on the right hand side of an expression. Every expression in C++ is either an lvalue or a ravlue. You can think of an lvalue as an object for which we can get its address in memory, while an rvalue is something for which we cannot get its address in the memory. As a rule of thumb, keep in mind that temporary objects, that are ideal candidates for moving instead of copying are rvalues.


auto var = 10;
int *ptr = &var;
auto ret = foo();

In the above examples var, ptr and ret are lvalues whereas the literal 10, address of var and return value of function foo are examples of rvalues.


C++ references allows you to create a second name/ alias for an already existing variable. In C++ you cannot have just a reference without it referring to any variable. In other words a reference should be initialized at the point of its declaration with some variable so that it can used as a reference/ alias to that variable.

int val = 10;
int &another_name = val;

In the above code snippet, another_name is a reference of type integer which is initialized with the variable val. Thus we can use another_name instead of val in order to read/ modify the value of variable val. In other words, another_name is bound to val.

Lvalue and Rvalue References

An lvalue reference is a reference/ alias to an lvalue and is denoted by a single ampersand ‘&’ while an rvalue reference is a reference/ alias to an rvalue and is denoted by double ampersand signs ‘&&’. Thus if you see a variable decorated with a single ampersand then it is an lvalue reference, whereas if it is adorned by double ampersand ‘&&’ then it is generally an rvalue reference. Notice, that I mentioned generally, because if the variable is deduced then there are a different set of rules. If ‘&&’ is used with a template variable then it has a different meaning. As per the term coined by Scott Meyer’s, if a variable or parameter is declared to have T&& for some deduced type T, then that variable or reference is a universal reference. A universal reference can bind to either an lvalue or an rvalue depending on reference collapsing rules. It is important to note the distinction between an rvalue reference and a universal reference. Note that there is no such thing as universal reference in the C++ standard but it is something which Scott has suggested in order to avoid confusion.

T&& is a universal reference if and only if –
1. T is deduced
2. It follows the strict syntax T&& or T&&… (In case of variadic template) and no other characters. The only creativity you can get to do is put one or many white spaces between T and && and that’s about it. No other characters or spaces are allowed; Otherwise it is treated as an rvalue reference, if syntactically correct.

Reference collapsing rules
1. T& & => T& // from C++98
2. T& && => T& // new for C++11
3. T&& & => T& // new for C++11
4. T&& && => T&& // new for C++11

Consider the cases 3 and 4 mentioned above. If we initialize a universal reference with an lvalue then it is an lvalue reference, on the contrary, if we initialize a universal reference with an rvalue then it is an rvalue reference. Thus even if a universal reference is decorated with &&, it might not always be an rvalue reference and it depends with what kind of value it is initialized with.

Temporary objects bind to rvalue references since they are rvalues. Thus, now we can overload functions to behave differently depending on whether it has been passed an lvalue reference or an rvalue reference.

The overloading rules for rvalues and lvalues are as follows:

  • If you implement only

    void foo(X&);
    void foo(X&&),

    the behavior is as in C++98: foo() can be called for lvalues but not for rvalues

  • If you implement

    void foo(const X&);
    void foo(X&&),

    the behavior is as in C++98: foo() can be called for rvalues and for lvalues. The compiler thinks it is safe to call the function for rvalues since X is const reference and it would not modify the state of the object being passed in.

  • If you implement

    void foo(X&);
    void foo(X&&);
    void foo(const X&)
    void foo(X&&);

    you can distinguish between dealing with rvalues and lvalues.

  • If you implement

    void foo(X&&);

    but neither
    void foo(X&)
    void foo(const X&),

    foo() can be called on rvalues, but trying to call it on lvalues will trigger compiler error.

As you probably know, in C++, a constructor is called when an object is created and a special copy constructor is called when a new object is created by copying from an existing object. Also an overloaded assignment operator is called when an existing object is initialized by copying/ assigning from another existing object of similar type.

Additionally, now, we can move temporary objects instead of copying, by implementing move constructors and move assignment operators. So whenever a situation arises, where a temporary object needs to be copied over and if a valid move constructor/ assignment operator exists then the appropriate move constructor or assignment operator is called automatically to increase performance. As per above overloading rules, if a class does not provide move semantics and has only usual copy constructor and copy assignment operator, then these would be called for rvalue references.

class HighResImage
    int x_dimension_;
    int y_dimension_;
    int* elements_;

    HighResImage(int x, int y) :
        x_dimension_{ x },
        y_dimension_{ y },
        elements_{ new int[x * y] };

    // Copy constructor
    HighResImage(const HighResImage& other) :
        x_dimension_{ other.x },
        y_dimension_{ other.y },
        elements_{ new int[other.x * other.y] }
        int total = x_dimension_ * y_dimension_;
        for (int index = 0; index < total; ++index)
            elements_[index] = other.elements_[index];

    // Move constructor
    HighResImage(HighResImage&& other) noexcept :
    x_dimension_{ other.x },
        y_dimension_{ other.y }
        elements_ = other.elements_;
        other.elements_ = nullptr;

    // Overloaded copy assignment operator
    HighResImage& operator=(const HighResImage& other)

    // Overloaded move assignment operator
    HighResImage& operator=(HighResImage&& other) noexcept

    // Destructor
        if (elements_)
            elements_ = nullptr;


Note that copy constructor and copy assignment operator functions takes a const reference whereas a move constructor and a move assignment operator does not. This is intentional because the move constructor and move assignment operator functions would need to modify the parameters (they will move them), hence the parameters cannot be const otherwise they would not be able to perform the move operation.

The only caution that move constructor and move assignment operation need to follow is that they should leave the moved from object in a valid state so that it’s destructor, when called does not crash, trying to deallocate memory which has already been moved or close a handle to a kernel object which has already been moved.


Many times situation will arise where you need to explicitly move an object instead of copying them since you know that you will no longer need that object. In other words you need to transfer an lvalue to an rvalue so that it can bind to an rvalue reference, if available. std::move will convert an lvalue to an rvalue. Its name is a bit misleading since it does not actually move an object but just converts an lvalue to an rvalue.

I have written 2 versions of a simple Matrix class to demonstrate and appreciate the performance impact offered by the move semantics. You can get the code on GitHub .One version of the Matrix class does not implement a move constructor while the other version implements it. Then a simple client code tries to use the Matrix class to create a matrix of dimension 1000 and assign it to another variable of type Matrix. The client code also profiles the time needed to create and copy the object in microseconds. By running the code, you can clearly see the performance gains achieved by using a move constructor.