15.4 — std::move

Once you start using move semantics more regularly, you’ll start to find cases where you want to invoke move semantics, but the objects you have to work with are l-values, not r-values. Consider the following swap function as an example:

Passed in two objects of type T (in this case, std::string), this function swaps their values by making three copies. Consequently, this program prints:

x: abc
y: de
x: de
y: abc

As we showed last lesson, making copies can be inefficient. And this version of swap makes 3 copies. That leads to a lot of excessive string creation and destruction, which is slow.

However, doing copies isn’t necessary here. All we’re really trying to do is swap the values of a and b, which can be accomplished just as well using 3 moves instead! So if we switch from copy semantics to move semantics, we can make our code more performant.

But how? The problem here is that parameters a and b are l-value references, not r-value references, so we don’t have a way to invoke the move constructor and move assignment operator instead of copy constructor and copy assignment. By default, we get the copy constructor and copy assignment behaviors. What are we to do?


In C++11, std::move is a standard library function that serves a single purpose -- to convert its argument into an r-value. We can pass an l-value to std::move, and it will return an r-value reference. std::move is defined in the utility header.

Here’s the same program as above, but with a myswap() function that uses std::move to convert our l-values into r-values so we can invoke move semantics:

This prints the same result as above:

x: abc
y: de
x: de
y: abc

But it’s much more efficient about it. When tmp is initialized, instead of making a copy of x, we use std::move to convert l-value variable x into an r-value. Since the parameter is an r-value, move semantics are invoked, and x is moved into tmp.

With a couple of more swaps, the value of variable x has been moved to y, and the value of y has been moved to x.

Another example

We can also use std::move when filling elements of a container, such as std::vector, with l-values.

In the following program, we first add an element to a vector using copy semantics. Then we add an element to the vector using move semantics.

This program prints:

Copying str
str: Knock
vector: Knock

Moving str
vector: Knock Knock

In the first case, we passed push_back() an l-value, so it used copy semantics to add an element to the vector. For this reason, the value in str is left alone.

In the second case, we passed push_back() an r-value (actually an l-value converted via std::move), so it used move semantics to add an element to the vector. This is more efficient, as the vector element can steal the string’s value rather than having to copy it. In this case, str is left empty.

At this point, it’s worth reiterating that std::move() gives a hint to the compiler that the programmer doesn’t need this object any more (at least, not in its current state). Consequently, you should not use std::move() on any persistent object you don’t want to modify, and you should not expect the state of any objects that have had std::move() applied to be the same after they are moved!

Move functions should always leave your objects in a well-defined state

As we noted in the previous lesson, it’s a good idea to always leave the objects being stolen from in some well-defined (deterministic) state. Ideally, this should be a “null state”, where the object is set back to its uninitiatized or zero state. Now we can talk about why: with std::move, the object being stolen from may not be a temporary after all. The user may want to reuse this (now empty) object again, or test it in some way, and can plan accordingly.

In the above example, string str is set to the empty string after being moved (which is what std::string always does after a successful move). This allows us to reuse variable str if we wish (or we can ignore it, if we no longer have a use for it).

Where else is std::move useful?

std::move can also be useful when sorting an array of elements. Many sorting algorithms (such as selection sort and bubble sort) work by swapping pairs of elements. In previous lessons, we’ve had to resort to copy-semantics to do the swapping. Now we can use move semantics, which is more efficient.

It can also be useful if we want to move the contents managed by one smart pointer to another.


std::move can be used whenever we want to treat an l-value like an r-value for the purpose of invoking move semantics instead of copy semantics.

15.5 -- std::unique_ptr
15.3 -- Move constructors and move assignment

100 comments to 15.4 — std::move

  • Parsa

    Does std::move return a new temporary and if so, how does that make it any faster?

    • `std::move` doesn't copy anything, it's just a fancy cast to an rvalue reference.
      Functions that have an overload for rvalue references can steal resources from the old object (eg. copying a pointer rather than an entire object), which is faster than copying in many cases.

  • Hello everyone. I have one doubt.
    move() of string will make original string variable empty
    but move() of int is not making original int variable empty.
    sample code for doubt-

    • Hello Ashish!

      Moving an object may or may not affect the moved-from object. If you move an `int` from one place to another, copying it is the fastest thing you can do. If you copied a string, you'd have to allocate new memory, which is slow. Since move semantics allow the moved-from object to be modified, `std::string`'s internal pointer can be copied to the moved-to string. Copying a pointer is way faster. The original string can't keep the pointer, because both `std::string`s would end up trying to delete the memory.

  • Serge

    Which way is it more correct to use r-value references along with std::move? Suppose I have the function createTexture() that returns an std::vector:

    they all compile and run, but for example 2 there is a partial corruption of data in the buffer referenced by tmp.

    • None of these should use `std::move`. Copy elision prevents all copies, there are no temporaries. I'm not sure what's happening in example 2, it appears the vector is dying in line 10 already.

  • Anthony

    I'm trying to understand why std::move is used in the following accumulate function:

    Would I be correct in describing the process as follows?:
    1) @std::move(init) creates a temporary object. It can use move semantics because it doesn't care about potentially 'ruining' the original @init object, and this way will be faster.
    2) the addition is performed, creating another temporary object, which is, again, an rvalue.
    3) the value of this object is moved, rather than copied, into @init -  which is fast.

    Thanks (as usual) :)

  • Vir1oN

    In addition to the previous question you answered below this chapter:

    As I’ve understood, move semantics are invoked here too, since 2 is an r-value?

  • yicho

    So you are saying all the classes in the std library have already implemented move constructors and move assignment operators and we don't have to implemented them ourselves? All we need to do is to convert function arguments to r-values using std::move?

  • jack price

    Hi chaps.
    first two examples, because you're using the keyword 'swap' in main() neither of the examples is actually calling the function 'swap()' but invoking std::swap, (which works fine!)

    x: abc
    y: de
    x: de
    y: abc

    • Alex

      Thanks for pointing this out. "swap" isn't a keyword, but you are correct regardless. I've updated the identifiers to avoid the naming collision.

      • jack price

        I'm a bit(!) fuzzy on the 'naming of the parts', what is the correct description of "swap" ?

        To make programs easier to read  I don't use for a variable name anything that is noticed by code::blocks' syntax highlighter. When one is not entirely sure what is going on in a program, (a not uncommon experience) it helps not having the added burden of deciding whether a word is a 'verb' or  a 'noun'

        keep up the good work, thanks for your patience.

      • Deepesh

        How does it call std::swap? There's no


        anywhere in the program. So by default, the compiler should look only in the global namespace and hence use the mentioned swap function.

        • Hi!

          This is made possible by argument-dependent lookup (ADL).
          If you call a function with an argument whose type is nested in a namespace, that namespace is considered for name lookup.

          The @swap that caused the trouble here, is declared in <string> or <basic_string>, which declare everything in the @std namespace. Since @std::string is also in that namespace, @swap can be looked up in @std.
          This version of @swap is preferred over the custom version, because it's not a template.

  • Perhaps the best explanation I have found for r-value/move semantics across various resources I consulted. Thanks Alex, for such awesome work!

  • in the example on vectors and strings being moved, i do not understand if a vector capacity and length is equal to 1 element that to push another would require a deallocation and a reallocation of a new array of 2 elements, how can str be moved if pushing the string "Knock" would require a new array as there is no individual pointers that point to every element of a vector only one and a length and how it can be can be moved in memory ?

    • @std::vector stores a native array. When vector A is move constructed from vector B, A can steal the array pointer and set B's pointer to nullptr. B is then empty, A has the elements that were previously stored in B.

      • ok i understand but what i meant is that is an individual element not a whole array how does it happens for V[1] only ?

        • If you move an individual element, that element's move constructor applies.
          If you move an @std::vector, the entire array is moved.

          • could you please explain more on how individual elements gets moved as i think they can only be copied in memory not moved, if

            vector A of 2 elements:
            A[0] -> address 01
            A[1] -> address 02

            another something:
            something -> address 10

            gets a push_back(std::move(something)) to steal something to a new A[2]
            so to make a move if my understanding is correct we need to have the same memory address of the new third member
            A[0] -> address 01
            A[1] -> address 02
            A[2] -> address 10

            sorry if my question feel a little dumb ...

            • Vector A has 2 elements, a third gets pushed.
              Vector A has to re-allocated its internal array. All elements get a new address, memory to store the third element exists (@A[2]), but isn't initialized. @something is moved into @A[2] by using @something's move constructor.
              @something is still at address 10, but might not be usable anymore, depending on its move constructor.
              All elements of @A have contiguous addresses, but not the same as before.

  • Asgar

    Hi Alex,

    About std::move, when you say, "We can pass an l-value to std::move, and it will return an r-value reference." did you mean it will return an r-value? Because, an r-value reference itself is an l-value which cannot be passed to a move constructor.

  • Gio

    Hi Alex,
    Can I use instead of std::move() a static_cast<T&&>?
    For example:

    • Nicolai

      Good question! I've just checked the definition of std::move and it is actually implemented by doing

      and if you take a look at the remove_reference template you will find out that it leads to the final implementation version of the std::move to this:

  • >> In C++11, std::move is a standard library function that serves a single purpose -- to convert its argument into an r-value.


    I'm curious. How can an l-value be converted to an r-value? I'd be very thankful if you can provide a toy example. With my below snippet, I get the error: Cannot bind rvalue reference of type 'int&&' to lvalue of type 'int'.

  • w4u

    v.push_back(str); // calls l-value version of push_back, which makes a copy
    is not correct, push_back take const reference, there is no copy involved.

    • nascardriver

      Hi w4u!

      The call itself doesn't create a copy, but our @std::vector stores @std::string elements, not references. It has to create a copy of the argument.

  • lpc

    "In the above example, vector str is set to the empty string after being moved (which is what std::vector always does after a successful move). This allows us to reuse the vector str if we wish (or we can ignore it, if we no longer have a use for it)."

    vector str? I think it should be string str here.

  • Isak

    Thanks Alex for the awesome tutorials so far! I have a question, can't std::move be used dangerously? Since we're moving our str in your program.  If we then plan to use str later on in the program, we can't since out string is moved! And iirc, that's UB right?

    Thanks in advance - Isak

    • nascardriver

      Hi Isak!

      You're right, this should really be included in this lesson. Certain functions of certain objects can be used after the object has been std::moved, but generally the object should not be used after having been std::moved.

      • Alex

        I'll make it explicit in the lesson, but this seems kind of obvious to me. :) You're telling the compiler, "it's okay to steal the contents of this object". After doing so, why would you reasonably expect the contents to still be there?

        Any class that implements move semantics should leave the object being stolen from in some deterministic state (whether that state is useful is another question).

        • Isak

          Thank you Alex and nascardriver for your response. I think it's good idea to make it explicit in this tutorial to avoid any confusion.
          And what you're stating Alex makes complete sense, but still I think it's a good idea to mention it. Anyhow, keep coming with the tutorials and I hope we will see more computer science (data structures and algorithms) related stuff in a near future.

          - Isak

  • Steve

    My understanding is that the assigmment after std::move in fact doesn't change content, but only changes address in pointers. So in short, the move only works for variable [including blocky content] on heap, but is helpless for variable on stack. Am I correct?
    For arrays, vectors, the actual implementation is that they stores pointers allocated on stack pointing to data store in heap. When move, the data in heap experience no change at all, the location of pointers on stack also don't change, the only thing changed is the addresses stored in those pointers on stack. Am I right?

    • Alex

      Mostly correct (as far as I understand). A few minor nitpicks:
      1) For std::vector, the element data is allocated on the heap. So std::vector is always movable because the pointer to the elements can be transferred to another vector.
      2) For std::array, the element data is allocated on the stack. Now you might think this makes std::move useless, but it doesn't -- those elements might be classes that contain dynamic memory. That dynamic memory can be moved at least, which is better than making copies.

  • Advice

    Hi Alex,
    It might be worth mention when vector(of ur own object) resize it use copy constructor if not move constructor is noexcept?

  • Levon

    Hello Alex, for the swap function, how do we know that the class T will have a move constructor defined?

    thank you

  • David

    For the second example, Visual Studio is calling std::swap(x, y) instead of swap(x, y). Should it being doing that without the ‘std::’ prefix? I have not added "using namespace std" anywhere, and the compiler is in Debug mode. Is renaming the function the only way around this?

    This prints:

    x: abc
    y: de
    x: de
    y: abc

    • Alex

      I see the same thing with Visual Studio 2017, but I'm not sure why this is occurring. It only seems to occur when swapping strings. When I swap other data types, the user-defined swap is called as expected.

      You can force your user-defined version of swap to be called by calling ::swap instead of just swap.

      • David

        Thank you for the tip and looking into that for me. I was really thrown off. I thought the lack of "using namespace std" was keeping me safe from naming conflicts. I may have to start prefixing everything with a scope qualifier from now on, just to sleep at night.

  • Name

    Is it good idea to use std::move on every assignment ?
    And about templates, do you need to write template<...> before every function or class to use template or you can make one template on the top of the program like variable?

    • Alex

      > Is it good idea to use std::move on every assignment ?

      No, it's only appropriate when you want to do a move, not a copy assignment.

      For templates, every function or class needs the template line.

  • I bet there should be

    in second example.
    Also, can you reply to my last e-mail?

  • Aitor

    Hi alex im having some troubles understanding one  little thing.
    when i use "std::move" to move  one ineger to another integer, and i print the first integer after move the resource from it , the value  of the integer seems to still there ,  the resource was not "stolen" from the integer as it should be, like in the string example. I put the code below:

    thank you.

    • Alex

      std::move just acts as a cast to an r-value reference. So when you do two = std::move(one), you're just casting one to be an rvalue reference, which has no impact upon the assignment in this case. That's why it acts identically to not using std::move.

      std::move is really meant to be used with classes, not fundamental types.

  • ali

    oh my god.
    it's incrediably amazing!

    so alex, do you know, how are c# and java approach to this context? Do they select copy method or move method?

    • Alex

      I don't know either Java or C# very well, so my answer may be incorrect. But my best understanding is that classes in java and C# both always use reference semantics for passing classes, so there's little to be gained by move semantics (since there are no temporary copies being made).

  • ashwin


    I have a question about the vector example. Tell me if my thinking is right.
    Strings are dynamically allocated and that is why using std::move in push_back to prevent creating a copy makes sense. It doesn't make sense to do a move for built in types like int and float as its not dynamically allocated. Am i right?

  • ashwin


    I have a doubt. In the first example where you swap two objects, what is the benefits of using a move constructor to copy constructor? ( for this statement  T tmp { std::move(a) }; )
    I am assuming the default generated copy and move constructors look like this:
    std::string(const string& rhs): buffer( new char[strlen(rhs)] ){ strcpy(buffer, rhs ); } //Copy ctor
    std::string(std::string&& rhs): buffer(rhs){ rhs = nullptr; } //Move coonstructor

    In copy constructor we are creating a new char* and in move we just transfer the ownership. Is that the only difference?

    • Alex

      Move constructors are much more efficient since we can just "transfer" the resource rather than making a copy.

      Think of it this way. You have an asparagus pie. You hate asparagus. Your friend loves asparagus pie, so you want him to have yours. What's easier?
      1) Give your asparagus pie to your friend.
      2) Go bake a second asparagus pie, give that pie to your friend, and then throw your pie in the trash.

      #1 is a move. #2 is a copy.

  • Seamus Callaghan

    Can I use std::move to return a local std::vector from a function without copying it?

  • apfelpektin

    in the first and second example the swap() in main uses variables a and b instead of the local x and y.

    in the second example also including the utility header is now redundant.

    i also wonder how the std::string instance str deals with the 'stealing'. does it allocate a new (empty) string for itself or does it just keep a null pointer internally until something new is assigned to it or copied/moved from it?
    maybe it even doesn't matter, since the function either will handle the move correctly if implemented, or just default to the copy semantics, so you don't have to know if a class can handle move semantics?

    • Alex

      Thanks for pointing out the typos. Fixed!

      How std::string is implemented is compiler specific. The nice thing about classes is that you don't need to worry about such things. As you note, if move semantics are implemented, they'll get invoked transparently. If they aren't, then copy semantics can be used.

  • Mauricio Mirabetti

    Also, If I may, I guess the phrase "And this version of std::swap makes 3 copies." refers to std::swap instead of this lesson specific version of swap function, which is what is being called. Perhaps std:: should be removed?

    Best regards.

  • aca4life

    two minor things:

    1) Just before section "std::move": "But how? ... so we can't don't have...": unwanted doubled negative.

    2) Code in section "Another example": r21 should also output the message (but is redundant, r17 does effectively the same)

  • Vinayak

    15.4 std::move is not mentioned on the INDEX page or Home Page of

Leave a Comment

Put all code inside code tags: [code]your code here[/code]