3

I try to understand the concept of move semantic and did some tests. I have the following function:

// testing the move semantic when passing 
// argument to be modified without copying

void process_copy( std::vector<int>&& aVec)
{
    std::cout << "Move semantic\n";
    aVec.push_back(42);
}

now in the main function, the following:

int main()
{
    std::vector<int> w_vec = {1,2,3,4,5};
    process_copy( std::move(w_vec));
}

I expect that the w_vec is now empty since I pass it with move cast (cast lvalue to rvalue). But the result is w_vec contains 6 elements now (42 has been added to the vector).

Something that I miss? Is std::vector is a moveable object?

JFMR
  • 23,265
  • 4
  • 52
  • 76
Elligno
  • 79
  • 2
  • `std::move()` just casts. You have to pass the result to something that will move-from, if you want to get moved-from, not just cast... lemme find one of the many duplicates. – underscore_d Jan 17 '21 at 17:26
  • 1
    Does this answer your question? [What is std::move(), and when should it be used?](https://stackoverflow.com/questions/3413470/what-is-stdmove-and-when-should-it-be-used) – underscore_d Jan 17 '21 at 17:28
  • "_argument to be modified without copying_" - so just pass a normal reference `& vec`, not an rvalue reference `&& vec`. Then you won't have to use `std::move()` to cast to an rvalue reference. Move semantics don't seem to mean what you think they mean, and `std::move()` alone will never move, just cast to an rvalue ref so the receiver _might_ move from same. – underscore_d Jan 17 '21 at 17:33
  • Just like your title said, it's semantics. No code to perform a move was called, so no move happened. – xaxxon Jan 18 '21 at 21:28

2 Answers2

15

An image of my CoreCpp 2019 t-shirt might be relevant here.

CoreCpp 2019 t-shirt

This is the front.

t-shirt front

It's interesting to note that this behavior of std::move was a bit surprising even for Howard Hinnant himself, the man behind rvalue and move semantics. However he got a very thorough answer there.

Amir Kirsh
  • 12,564
  • 41
  • 74
  • 1
    I think it is safe to say that I was never surprised by the behavior I designed. Self-answer is an [approved technique for disseminating knowledge](https://stackoverflow.com/help/self-answer). – Howard Hinnant Jan 19 '21 at 14:48
  • @HowardHinnant It was a joke. I'm also using occasionally the technique of answering my own questions. Hope it was not an offending joke, if it is I can of course edit to rephrase or remove it. Anyway, your question and answer is a great resource on the subject, if the explanation on the t-shirt I've posted is not enough. – Amir Kirsh Jan 19 '21 at 17:02
  • No, I'm not offended at all. And thanks for the [link](https://stackoverflow.com/q/21358432/576911)! – Howard Hinnant Jan 19 '21 at 17:41
4

What you may be missing is that you are just binding an rvalue reference to the vector you pass; you are moving no vector object at all.

The process_copy() parameter is of type std::vector<int>&&, i.e., an rvalue reference to std::vetor<int>:

void process_copy(std::vector<int>&& aVec)

By using std::move() when calling process_copy() as in:

process_copy(std::move(w_vec));

You are just making it possible to bind this reference – i.e., process_copy()'s parameter, aVec – to the argument – i.e., the vector w_vec. That is, the following does not compile:

process_copy(w_vec);

Because you can't bind an rvalue reference (aVec) to an lvalue (w_vec).


If you want the vector argument w_vec to be moved when calling process_copy(), then you could have the function to take an std::vector<int> by value instead and move construct this parameter at the moment of calling the function:

void process_copy(std::vector<int> aVec) // <-- not a reference
{
    aVec.push_back(42);
}

By marking the vector argument with std::move() when calling this process_copy(), the parameter aVec will be move constructed – so the vector argument will end up in a moved-from state.

JFMR
  • 23,265
  • 4
  • 52
  • 76