Почему std :: move копирует содержимое для аргумента функции rvalue или const lvalue? - PullRequest
1 голос
/ 10 февраля 2020

Если я использую std :: move для стекового объекта в текущей области действия, содержимое перемещается по назначению, оставляя источник пустым.

#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;
}

Результат:

vec[0]: stackoverflow
str: 

Если я использую std :: move для аргументов функции rvalue или const lvalue, содержимое копируется.

#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;
}

Результат:

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

Почему поведение std :: move отличается?

Ответы [ 2 ]

3 голосов
/ 10 февраля 2020

Вам необходимо использовать std::move, если значение связано с переменной, даже если оно объявлено как rvalue admfernce (&&). т.е. должно быть:

void process_copy(std::vector<int> && vec_)
{
    std::vector<int> vec(std::move(vec_));
    ...
}
1 голос
/ 10 февраля 2020

Ваш вектор фактически скопирован, а не перемещен. Причина этого в том, что, хотя объявлено как ссылка на rvalue, vec_ обозначает выражение lvalue внутри тела функции. Таким образом, вызывается конструктор копирования std::vector, а не конструктор перемещения. Причина этого в том, что vec_ теперь является именованным значением, а rvalues ​​не может иметь имен, поэтому оно сворачивается в lvalue. По этой причине следующий код не удастся скомпилировать:

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

Чтобы устранить эту проблему, необходимо снова сделать vec_ безымянным , вызвав std::move(vec_).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...