4

This code works as expected (online here). At the end v is empty and w is not empty as it has pilfered the contents of v.

    vector<int> v;
    v.push_back(1);
    cout << "v.size(): " << v.size() << endl;
    auto vp = move(v);
    vector<int> w(vp);
    cout << "w.size(): " << w.size() << endl;
    cout << "v.size(): " << v.size() << endl;

But if I replace auto vp=move(v) with

    vector<int> && vp = move (v);

Then it doesn't move. Instead it copies and both vectors are non-empty at the end. As shown here.

Clarification: More specifically, what is the auto-derived type of vp? If it's not vector<int> &&, then what else could it be? Why do the two examples give different results despite being so similar?

Extra: I also tried this, and it still copied instead of moving

    std :: remove_reference< vector<int> > :: type && vp = move(v);
Alex Bitek
  • 6,529
  • 5
  • 47
  • 77
Aaron McDaid
  • 26,501
  • 9
  • 66
  • 88

3 Answers3

13

Edit for OP's clarification: the auto-derived type of move(v) is vector<int>. See C++11 "auto" semantics.

The 1st example does this:

move 'v' into 'vp'
copy 'vp' into 'w'

and the 2nd example does this:

set 'vp' as rvalue-reference of 'v'
copy 'vp' (which is 'v') into 'w'

What std:move does is simply casting a type to an rvalue (See What is std::move(), and when should it be used?). Therefore, in

vector<int>&& vp = move(v);

it's just setting the rvalue-reference vp to v and do nothing else. Also, an rvalue-reference is an lvalue (it has a name), so

vector<int> w(vp);

will call the copy constructor to copy vp (which is v) into w.

It will call the move constructor if you make vp an rvalue (Example):

vector<int> w(move(vp))

You may want to read this: C++ Rvalue References Explained.

Community
  • 1
  • 1
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
  • This doesn't really explain why one way works but the other doesn't. – Seth Carnegie Dec 19 '11 at 01:06
  • 2
    But it's not calling the copy constructor in the first example. `auto vp = move(v); vector w(vp)` works (the data is pilfered). Why does this work? What is the auto-derived type of vp? – Aaron McDaid Dec 19 '11 at 01:07
  • @AaronMcDaid: It *is* calling the copy constructor, just not calling `v`'s. See update. – kennytm Dec 19 '11 at 01:13
  • Looking back on my own question from two years ago. I can see that I was under the impression that `move` actually did something and had side effects. I also assumed that the `auto` type would be a reference. Wrong on both counts. – Aaron McDaid Sep 27 '13 at 23:34
2

In the first case:

auto vp = move(v);

is equivalent to:

vector<int> vp = move(v);

This invokes the move constructor, since move(v) has type vector<int>&&, hence vp ends up pilfering the contents of v.

In the second case:

vector<int>&& vp = move(v);

just makes vp an r-value reference to v. This doesn't result in the move constructor or copy constructor being called, and nothing is pilfered.

Stuart Golodetz
  • 20,238
  • 4
  • 51
  • 80
1
auto vp = move(v);

Is creating a new vector<int> and calling it's move constructor:

vector(const vector<T>&& other);

Which will steal the contents of v.

So type of 'vp' is simply vector<int> .. no references involved:

vector<int> vp;

It's 'moving' the internals .. not the actual vector itself.

So &vp will be different to &v .. but the contents will move across.

matiu
  • 7,469
  • 4
  • 44
  • 48