766
  1. What is it?
  2. What does it do?
  3. When should it be used?

Good links are appreciated.

Basilevs
  • 18,490
  • 15
  • 51
  • 98
  • 49
    Bjarne Stroustrup explains move in [A Brief Introduction to Rvalue References](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html#Move_Semantics) – DumbCoder Aug 05 '10 at 09:49
  • 2
    [Move semantics](http://stackoverflow.com/q/3106110/125562) – Basilevs Sep 11 '14 at 04:12
  • 15
    This question is referring to `std::move(T && t)`; there also exists a `std::move(InputIt first, InputIt last, OutputIt d_first)` which is an algorithm related to `std::copy`. I point it out so others aren't as confused as I was when first confronted with a `std::move` taking three arguments. http://en.cppreference.com/w/cpp/algorithm/move – josaphatv Oct 17 '16 at 22:48
  • 1
    Recommend reading this if you don't have much of an idea what lvalue and rvalue references mean https://www.internalpointers.com/post/understanding-meaning-lvalues-and-rvalues-c – Karan Singh Jun 25 '20 at 15:22

8 Answers8

352

Wikipedia Page on C++11 R-value references and move constructors

  1. In C++11, in addition to copy constructors, objects can have move constructors.
    (And in addition to copy assignment operators, they have move assignment operators.)
  2. The move constructor is used instead of the copy constructor, if the object has type "rvalue-reference" (Type &&).
  3. std::move() is a cast that produces an rvalue-reference to an object, to enable moving from it.

It's a new C++ way to avoid copies. For example, using a move constructor, a std::vector could just copy its internal pointer to data to the new object, leaving the moved object in an moved from state, therefore not copying all the data. This would be C++-valid.

Try googling for move semantics, rvalue, perfect forwarding.

Noch
  • 5
  • 3
Scharron
  • 15,365
  • 6
  • 40
  • 63
  • 44
    Move-semantics require the moved object remain *valid*, which is not an incorrect state. (Rationale: It still has to destruct, make it work.) – GManNickG Aug 05 '10 at 16:37
  • 15
    @GMan: well, it has to be in a state that is safe to destruct, but, AFAIK, it does not have to be usable for anything else. – Zan Lynx Oct 04 '11 at 19:15
  • 8
    @ZanLynx: Right. Note that the standard library additionally requires moved objects be assignable, but this is only for objects used in the stdlib, not a general requirement. – GManNickG Oct 04 '11 at 19:44
  • 30
    -1 *"std::move() is the C++11 way to use move semantics"* Please fix that. `std::move()` is not the way to use move semantics, move semantics are performed transparently to the programmer. `move` its only a cast to pass a value from one point to another where the original lvalue will no longer be used. – Manu343726 Jul 03 '14 at 19:35
  • 21
    I'd go further. `std::move` itself does "nothing" - it has zero side effects. It just signals to the compiler that the programmer doesn't care what happens to that object any more. i.e. it gives *permission* to other parts of the software to move from the object, but it doesn't require that it be moved. In fact, the recipient of an rvalue reference doesn't have to make any promises about what it will or will not do with the data. – Aaron McDaid Aug 20 '15 at 14:17
  • *"The move constructor is used instead of the copy constructor, if the object has type "rvalue-reference""* Pardon the nitpicking, but expressions (any function argument is an expression rather than an object) can't have reference types. So rather than *"has type "rvalue-reference""* a more precise wording would be *"has "rvalue" value category"* or something similar. – HolyBlackCat Feb 18 '19 at 16:39
  • @Manu343726 Care to explain to me how what you just described isn't a literal move? That's literally what move is, moving out an lvalue, and after you move it, it's unusable past that... I don't care if std::move isn't the thing that does the moving. It IS a move. Don't believe me? Read it's name. – Purple Ice Feb 18 '19 at 17:03
  • 5
    Oh how I lament the ridiculous things that C++ must invent to replace the simplicity of C! `struct mystruct * newstruct = oldstruct;` <== Look, I just moved the contents of `oldstruct` to `newstruct` in C by reassigning a pointer! – Gabriel Staples Apr 07 '20 at 18:43
  • I do have a question I didn't find so far.an answer `std::move` does nothing. Ok, I've read this everywhere but returning a r-value reference means that you somehow underlined the fact that the move constructor (if any) should execute. If there is no move constructor, what would happen? Is something right from what I've written here? – Cătălina Sîrbu Apr 17 '20 at 19:18
  • I've been testing `std::move()` over and over with move constructor, it does nothing! The remaining `r-value` can be used arbitrarily, the behavior of move contructor depends totally on the implementation. I coudn't find a benefit on it yet. – Maf Feb 26 '21 at 13:18
320

1. "What is it?"

While std::move() is technically a function - I would say it isn't really a function. It's sort of a converter between ways the compiler considers an expression's value.

2. "What does it do?"

The first thing to note is that std::move() doesn't actually move anything. It changes an expression from being an lvalue (such as a named variable) to being an xvalue. An xvalue tells the compiler:

You can plunder me, move anything I'm holding and use it elsewhere (since I'm going to be destroyed soon anyway)".

in other words, when you use std::move(x), you're allowing the compiler to cannibalize x. Thus if x has, say, its own buffer in memory - after std::move()ing the compiler can have another object own it instead.

You can also move from a prvalue (such as a temporary you're passing around), but this is rarely useful.

3. "When should it be used?"

Another way to ask this question is "What would I cannibalize an existing object's resources for?" well, if you're writing application code, you would probably not be messing around a lot with temporary objects created by the compiler. So mainly you would do this in places like constructors, operator methods, standard-library-algorithm-like functions etc. where objects get created and destroyed automagically a lot. Of course, that's just a rule of thumb.

A typical use is 'moving' resources from one object to another instead of copying. @Guillaume links to this page which has a straightforward short example: swapping two objects with less copying.

template <class T>
swap(T& a, T& b) {
    T tmp(a);   // we now have two copies of a
    a = b;      // we now have two copies of b (+ discarded a copy of a)
    b = tmp;    // we now have two copies of tmp (+ discarded a copy of b)
}

using move allows you to swap the resources instead of copying them around:

template <class T>
swap(T& a, T& b) {
    T tmp(std::move(a));
    a = std::move(b);   
    b = std::move(tmp);
}

Think of what happens when T is, say, vector<int> of size n. In the first version you read and write 3*n elements, in the second version you basically read and write just the 3 pointers to the vectors' buffers, plus the 3 buffers' sizes. Of course, class T needs to know how to do the moving; your class should have a move-assignment operator and a move-constructor for class T for this to work.

einpoklum
  • 86,754
  • 39
  • 223
  • 453
  • 8
    For a long time I've heard of these move semantics, I never looked into them. From this description you've given it just seems like it's a shallow copy instead of a deep copy. – Zebrafish Dec 30 '16 at 10:52
  • 17
    @TitoneMaurice: Except that it's not a copy - as the original value is no longer usable. – einpoklum Dec 30 '16 at 11:52
  • 5
    @Zebrafish you couldn't be more wrong. A shallow copy leaves the original in the exact same state, a move usually results in the original being empty or in an otherwise valid state. – rubenvb Jan 10 '18 at 22:38
  • 40
    @rubenvb Zebra isn't entirely wrong. While it's true that the original cannabilised object is usually deliberately sabotaged to avoid confusing errors (e.g. set its pointers to nullptr to signal that it no longer owns the pointees), the fact that the whole move is implemented by simply copying a pointer from the source to the destination (and deliberately avoiding doing anything with the pointee) is indeed reminiscent of a shallow copy. In fact, I would go so far as to say that a move _is_ a shallow copy, followed optionally by a partial self-destruct of the source. _(cont.)_ – Lightness Races in Orbit Nov 01 '18 at 18:54
  • 7
    _(cont.)_ If we permit this definition (and I rather like it), then @Zebrafish's observation isn't wrong, just slightly incomplete. – Lightness Races in Orbit Nov 01 '18 at 18:55
  • @LightnessRacesinOrbit You're forgetting the implied ownership transfer of a move. If an owning object is moved from, it loses ownership, in shrill contrast with a shallow copy. – rubenvb Nov 02 '18 at 07:54
  • 4
    @rubenvb Correct at a higher level of abstraction but if we're talking about how it's implemented then the fundamental similarities cannot be ignored, at least if our goal is to explain what C++ move semantics really _are_ in practical terms. Even then, I believe the partial self-destruct of the source covers the loss of ownership angle. – Lightness Races in Orbit Nov 02 '18 at 10:37
  • @rubenvb: This discussion seems to belong in chat (unless you think I should change my answer). – einpoklum Nov 02 '18 at 10:49
  • I don't think your answer needs to be changed, my original comment here was directed at Zebrafish who has now morphed into Lightness Races In Orbit. I also can't seem to find the "move to chat" button that I vaguely remember being added to long comment discussions. @Lightness Anyhoo, I still think passing of a move operation as a glorified shallow copy is dangerous, especially to beginners. The optionality of the "self-destruct of the source" as you frame it depends highly on the ownership of the resources shallowly copied, and as such I don't think it can be labeled as optional in general. – rubenvb Nov 02 '18 at 11:13
  • @einpoklum It's true we've got a bit off-topic. – Lightness Races in Orbit Nov 02 '18 at 11:22
  • @aschepler: Edited as per your suggestion. – einpoklum Feb 18 '19 at 20:50
153

You can use move when you need to "transfer" the content of an object somewhere else, without doing a copy (i.e. the content is not duplicated, that's why it could be used on some non-copyable objects, like a unique_ptr). It's also possible for an object to take the content of a temporary object without doing a copy (and save a lot of time), with std::move.

This link really helped me out :

http://thbecker.net/articles/rvalue_references/section_01.html

I'm sorry if my answer is coming too late, but I was also looking for a good link for the std::move, and I found the links above a little bit "austere".

This puts the emphasis on r-value reference, in which context you should use them, and I think it's more detailed, that's why I wanted to share this link here.

q-l-p
  • 3,262
  • 3
  • 12
  • 32
Guillaume
  • 1,631
  • 2
  • 15
  • 20
  • 27
    Nice link. I always found the wikipedia article, and other links that I stumbled across rather confusing since they just throw facts at you, leaving it to you to figure out what the actual meaning/rationale is. While "move semantics" in a constructor is rather obvious, all those details about passing &&-values around are not... so the tutorial-style description was very nice. – Christian Stieber Jul 15 '12 at 12:12
82

Q: What is std::move?

A: std::move() is a function from the C++ Standard Library for casting to a rvalue reference.

Simplisticly std::move(t) is equivalent to:

static_cast<T&&>(t);

An rvalue is a temporary that does not persist beyond the expression that defines it, such as an intermediate function result which is never stored in a variable.

int a = 3; // 3 is a rvalue, does not exist after expression is evaluated
int b = a; // a is a lvalue, keeps existing after expression is evaluated

An implementation for std::move() is given in N2027: "A Brief Introduction to Rvalue References" as follows:

template <class T>
typename remove_reference<T>::type&&
std::move(T&& a)
{
    return a;
}

As you can see, std::move returns T&& no matter if called with a value (T), reference type (T&), or rvalue reference (T&&).

Q: What does it do?

A: As a cast, it does not do anything during runtime. It is only relevant at compile time to tell the compiler that you would like to continue considering the reference as an rvalue.

foo(3 * 5); // obviously, you are calling foo with a temporary (rvalue)

int a = 3 * 5;
foo(a);     // how to tell the compiler to treat `a` as an rvalue?
foo(std::move(a)); // will call `foo(int&& a)` rather than `foo(int a)` or `foo(int& a)`

What it does not do:

  • Make a copy of the argument
  • Call the copy constructor
  • Change the argument object

Q: When should it be used?

A: You should use std::move if you want to call functions that support move semantics with an argument which is not an rvalue (temporary expression).

This begs the following follow-up questions for me:

  • What is move semantics? Move semantics in contrast to copy semantics is a programming technique in which the members of an object are initialized by 'taking over' instead of copying another object's members. Such 'take over' makes only sense with pointers and resource handles, which can be cheaply transferred by copying the pointer or integer handle rather than the underlying data.

  • What kind of classes and objects support move semantics? It is up to you as a developer to implement move semantics in your own classes if these would benefit from transferring their members instead of copying them. Once you implement move semantics, you will directly benefit from work from many library programmers who have added support for handling classes with move semantics efficiently.

  • Why can't the compiler figure it out on its own? The compiler cannot just call another overload of a function unless you say so. You must help the compiler choose whether the regular or move version of the function should be called.

  • In which situations would I want to tell the compiler that it should treat a variable as an rvalue? This will most likely happen in template or library functions, where you know that an intermediate result could be salvaged.

Yoon5oo
  • 489
  • 5
  • 11
Christopher Oezbek
  • 17,629
  • 3
  • 48
  • 71
  • 4
    Big +1 for code examples with semantics in comments. The other top answers define std::move using "move" itself - doesn't really clarify anything! --- I believe it's worth mentioning that not making a copy of the argument means that the original value cannot be reliably used. – t.y Jun 07 '18 at 18:48
  • you should add explanation of what salvaging is – Ulterior Nov 10 '20 at 11:53
36

std::move itself doesn't really do much. I thought that it called the moved constructor for an object, but it really just performs a type cast (casting an lvalue variable to an rvalue so that the said variable can be passed as an argument to a move constructor or assignment operator).

So std::move is just used as a precursor to using move semantics. Move semantics is essentially an efficient way for dealing with temporary objects.

Consider Object A = B + C + D + E + F;

This is nice looking code, but E + F produces a temporary object. Then D + temp produces another temporary object and so on. In each normal "+" operator of a class, deep copies occur.

For example

Object Object::operator+ (const Object& rhs) {
    Object temp (*this);
    // logic for adding
    return temp;
}

The creation of the temporary object in this function is useless - these temporary objects will be deleted at the end of the line anyway as they go out of scope.

We can rather use move semantics to "plunder" the temporary objects and do something like

 Object& Object::operator+ (Object&& rhs) {
     // logic to modify rhs directly
     return rhs;
 }

This avoids needless deep copies being made. With reference to the example, the only part where deep copying occurs is now E + F. The rest uses move semantics. The move constructor or assignment operator also needs to be implemented to assign the result to A.

einpoklum
  • 86,754
  • 39
  • 223
  • 453
user929404
  • 1,805
  • 21
  • 26
  • 3
    you spoke about move semantics . you should add to your answer as how std::move can be used because the question asks about that. – Koushik Shetty Jun 05 '13 at 08:01
  • 2
    @Koushik std::move doesnt do much - but is used to implement move semantics. If you don't know about std::move, you probably dont know move semantics either – user929404 Jun 05 '13 at 08:56
  • 1
    "doesnt do much"(yes just a static_cast to to a rvalue reference). what actually does it do and y it does is what the OP asked. you need not know how std::move works but you got to know what move semantics does. furthermore, "but is used to implement move semantics" its the otherway around. know move semantics and you'l understand std::move otherwise no. move just helps in movement and itself uses move semantics. std::move does nothing but convert its argument to rvalue reference, which is what move semantics require. – Koushik Shetty Jun 05 '13 at 09:08
  • 11
    "but E + F produces a temporary object" - Operator `+` goes left to right, not right to left. Hence `B+C` would be first! – Ajay Oct 15 '15 at 07:20
  • only your answer explained it to me – Ulterior Nov 10 '20 at 11:53
9

"What is it?" and "What does it do?" has been explained above.

I will give a example of "when it should be used".

For example, we have a class with lots of resource like big array in it.

class ResHeavy{ //  ResHeavy means heavy resource
    public:
        ResHeavy(int len=10):_upInt(new int[len]),_len(len){
            cout<<"default ctor"<<endl;
        }

        ResHeavy(const ResHeavy& rhs):_upInt(new int[rhs._len]),_len(rhs._len){
            cout<<"copy ctor"<<endl;
        }

        ResHeavy& operator=(const ResHeavy& rhs){
            _upInt.reset(new int[rhs._len]);
            _len = rhs._len;
            cout<<"operator= ctor"<<endl;
        }

        ResHeavy(ResHeavy&& rhs){
            _upInt = std::move(rhs._upInt);
            _len = rhs._len;
            rhs._len = 0;
            cout<<"move ctor"<<endl;
        }

    // check array valid
    bool is_up_valid(){
        return _upInt != nullptr;
    }

    private:
        std::unique_ptr<int[]> _upInt; // heavy array resource
        int _len; // length of int array
};

Test code:

void test_std_move2(){
    ResHeavy rh; // only one int[]
    // operator rh

    // after some operator of rh, it becomes no-use
    // transform it to other object
    ResHeavy rh2 = std::move(rh); // rh becomes invalid

    // show rh, rh2 it valid
    if(rh.is_up_valid())
        cout<<"rh valid"<<endl;
    else
        cout<<"rh invalid"<<endl;

    if(rh2.is_up_valid())
        cout<<"rh2 valid"<<endl;
    else
        cout<<"rh2 invalid"<<endl;

    // new ResHeavy object, created by copy ctor
    ResHeavy rh3(rh2);  // two copy of int[]

    if(rh3.is_up_valid())
        cout<<"rh3 valid"<<endl;
    else
        cout<<"rh3 invalid"<<endl;
}

output as below:

default ctor
move ctor
rh invalid
rh2 valid
copy ctor
rh3 valid

We can see that std::move with move constructor makes transform resource easily.

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. Previously, 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.

Cited:

Lightness Races in Orbit
  • 358,771
  • 68
  • 593
  • 989
Jayhello
  • 3,887
  • 3
  • 34
  • 44
2

std::move itself does nothing rather than a static_cast. According to cppreference.com

It is exactly equivalent to a static_cast to an rvalue reference type.

Thus, it depends on the type of the variable you assign to after the move, if the type has constructors or assign operators that takes a rvalue parameter, it may or may not steal the content of the original variable, so, it may leave the original variable to be in an unspecified state:

Unless otherwise specified, all standard library objects that have been moved from being placed in a valid but unspecified state.

Because there is no special move constructor or move assign operator for built-in literal types such as integers and raw pointers, so, it will be just a simple copy for these types.

Yoon5oo
  • 489
  • 5
  • 11
Tiger Yu
  • 676
  • 2
  • 5
0

Here is a full example, using std::move for a (simple) custom vector

Expected output:

 c: [10][11]
 copy ctor called
 copy of c: [10][11]
 move ctor called
 moved c: [10][11]

Compile as:

  g++ -std=c++2a -O2 -Wall -pedantic foo.cpp

Code:

#include <iostream>
#include <algorithm>

template<class T> class MyVector {
private:
    T *data;
    size_t maxlen;
    size_t currlen;
public:
    MyVector<T> () : data (nullptr), maxlen(0), currlen(0) { }
    MyVector<T> (int maxlen) : data (new T [maxlen]), maxlen(maxlen), currlen(0) { }

    MyVector<T> (const MyVector& o) {
        std::cout << "copy ctor called" << std::endl;
        data = new T [o.maxlen];
        maxlen = o.maxlen;
        currlen = o.currlen;
        std::copy(o.data, o.data + o.maxlen, data);
    }

    MyVector<T> (const MyVector<T>&& o) {
        std::cout << "move ctor called" << std::endl;
        data = o.data;
        maxlen = o.maxlen;
        currlen = o.currlen;
    }

    void push_back (const T& i) {
        if (currlen >= maxlen) {
            maxlen *= 2;
            auto newdata = new T [maxlen];
            std::copy(data, data + currlen, newdata);
            if (data) {
                delete[] data;
            }
            data = newdata;
        }
        data[currlen++] = i;
    }

    friend std::ostream& operator<<(std::ostream &os, const MyVector<T>& o) {
        auto s = o.data;
        auto e = o.data + o.currlen;;
        while (s < e) {
            os << "[" << *s << "]";
            s++;
        }
        return os;
    }
};

int main() {
    auto c = new MyVector<int>(1);
    c->push_back(10);
    c->push_back(11);
    std::cout << "c: " << *c << std::endl;
    auto d = *c;
    std::cout << "copy of c: " << d << std::endl;
    auto e = std::move(*c);
    delete c;
    std::cout << "moved c: " << e << std::endl;
}
Neil McGill
  • 2,143
  • 1
  • 19
  • 23