Move semantics with std::vector misunderstanding when passing to a function

Viewed 432

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?

2 Answers

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.

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.

Related