r18ul
r18ul

Reputation: 1064

Why does std::move copy contents for a rvalue or const lvalue function argument?

If I use std::move on a stack object in the current scope, the contents are moved to destination leaving the source empty.

#include <iostream>
#include <string>
#include <utility>
#include <vector>

int main()
{
    std::string str("stackoverflow");

    std::vector<std::string> vec;
    vec.emplace_back(std::move(str));
    std::cout << "vec[0]: " << vec[0] << std::endl;

    std::cout << "str: " << str << std::endl;
}

Result:

vec[0]: stackoverflow
str: 

If I use the std::move for a rvalue or const lvalue function arguments, the contents are copied.

#include <iostream>
#include <memory>
#include <vector>
#include <utility>

void process_copy(std::vector<int> const & vec_)
{
    std::vector<int> vec(vec_);
    vec.push_back(22);
    std::cout << "In process_copy (const &): " << std::endl;
    for(int & i : vec)
        std::cout << i << ' ';
    std::cout << std::endl;
}

void process_copy(std::vector<int> && vec_)
{
    std::vector<int> vec(vec_);
    vec.push_back(99);
    std::cout << "In process_copy (&&): " << std::endl;
    for(int & i : vec)
        std::cout << i << ' ';
    std::cout << std::endl;
}

int main()
{
    std::vector<int> v = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    process_copy(std::move(v));

    std::cout << "In main: " << std::endl;
    for(int & i : v)
        std::cout << i << ' ';
    std::cout << std::endl;
    std::cout << "size: " << v.size() << std::endl;
}

Result:

In process_copy (&&): 
0 1 2 3 4 5 6 7 8 9 99 
In main: 
0 1 2 3 4 5 6 7 8 9 
size: 10

Why is the behavior of std::move different?

Upvotes: 0

Views: 1083

Answers (2)

Timo
Timo

Reputation: 9825

Your vector is actually copied, not moved. The reason for this is, although declared as an rvalue reference, vec_ denotes an lvalue expression inside the function body. Thus the copy constructor of std::vector is invoked, and not the move constructor. The reason for this is, that vec_ is now a named value, and rvalues cannot have names, so it collapses to an lvalue. The following code will fail to compile because of this reason:

void foo(int&& i)
{
    int&& x = i;
}

In order to fix this issue, you have to make vec_ nameless again, by calling std::move(vec_).

Upvotes: 1

dewaffled
dewaffled

Reputation: 2973

You need to use std::move if the value is bound to a variable even it is declared as rvalue revefernce (&&). i.e. it should be:

void process_copy(std::vector<int> && vec_)
{
    std::vector<int> vec(std::move(vec_));
    ...
}

Upvotes: 3

Related Questions