Почему использование std :: move, несмотря на то, что параметр является ссылкой на r-значение - PullRequest
0 голосов
/ 01 марта 2019

Я запутался в использовании std :: move () в приведенном ниже коде:

Если я раскомментирую строку в (2), результат будет: 1 2 3, но если я раскомментирую строку в (1) выводене было бы ничего, что означало бы, что конструктор перемещения std::vector был вызван!

Почему мы должны сделать еще один вызов std::move в (1), чтобы вызвать конструктор перемещения из std::vector?

Что я понял, что std::move получает r-value его параметра, поэтому, почему мы должны получить r-value из r-value в (1)?

Я думаю, что эта строка _v = rv; в (2) более логична и должна вызывать std::vector конструктор перемещения для вызова без std::move, поскольку rv сама по себе является ссылкой r-value в первую очередь.

template <class T>
class A
{
public:
    void set(std::vector<T> & lv)
    {

    }  
    void set(std::vector<T> && rv)
    {           
        //_v = std::move(rv);          (1)
        //_v = rv;                     (2)
    }

private:
    std::vector<T> _v;
};

int main()
{
    std::vector<int> vec{1,2,3};
    A<int> a;

    a.set(std::move(vec));
    for(auto &item : vec)
        cout << item << " ";
    cout << endl;

    return 0;
}

1 Ответ

0 голосов
/ 01 марта 2019

Каждый именованный объект является Lvalue ref относительно Lvalue :

имя переменной, функции, объекта параметра шаблона (начиная с C ++ 20) иличлен данных, независимо от типа, такой как std :: cin или std :: endl. Даже если тип переменной является ссылкой на rvalue, выражение , состоящее из его имени, является выражением lvalue ;

vector имеет две перегрузки оператора присваиванияодин для ссылки на Lvalue, а другой для ссылки на Rvalue.

vector::operator=(const vector&) // copy assignment operator
vector::operator=(vector&&) // move assignment operator

Перегрузка, которая принимает ссылку на Lvalue, вызывается, когда Lvalue передается в качестве аргумента для operator=. Подробности здесь

, когда функция имеет как ссылочные перегрузки rvalue, так и опорные ссылки lvalue, ссылочная перегрузка rvalue связывается с rvalue (включая оба значения prvalues ​​и xvalue), в то время как перегрузка ссылки lvalue связываетсяв lvalues ​​

По std::move(rv); вы приводите rv - Lvalue к Rvalue, и вызывается operator=, который принимает Rvalue.В противном случае Lvalue связывается со ссылкой Lvalue, а вектор копируется вместо перемещения.

...