Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why to use std::move despite the parameter is an r-value reference

I am confused about using std::move() in below code:

If I uncomment line at (2) the output would be: 1 2 3 but if I uncomment line at (1) output would be nothing which means that move constructor of std::vector was called!

Why do we have to make another call to std::move at (1) to make move constructor of std::vector to be called?

What I understood that std::move get the r-value of its parameter so, why we have to get the r-value of r-value at (1)?

I think this line _v = rv; at (2) is more logical and should make std::vector move constructor to be called without std::movebecause rv itself is r-value reference in the first place.

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;
}
like image 245
Islam Abdeen Avatar asked Mar 01 '19 20:03

Islam Abdeen


People also ask

What is the difference between std :: forward and std :: move?

std::move takes an object and casts it as an rvalue reference, which indicates that resources can be "stolen" from this object. std::forward has a single use-case: to cast a templated function parameter of type forwarding reference ( T&& ) to the value category ( lvalue or rvalue ) the caller used to pass it.

Should I return std :: move?

std::move is totally unnecessary when returning from a function, and really gets into the realm of you -- the programmer -- trying to babysit things that you should leave to the compiler.

Why do we need rvalue references?

Rvalue references allow programmers to avoid logically unnecessary copying and to provide perfect forwarding functions. They are primarily meant to aid in the design of higer performance and more robust libraries.

Why is std :: move necessary?

std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object.


1 Answers

Every named object is Lvalue ref about Lvalue:

the name of a variable, a function, a template parameter object (since C++20), or a data member, regardless of type, such as std::cin or std::endl. Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression;

vector has two overloads of assignment operator, one for Lvalue reference and another for Rvalue reference.

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

Overload which takes Lvalue reference is called when Lvalue is passed as argument for operator=. Details here

when a function has both rvalue reference and lvalue reference overloads, the rvalue reference overload binds to rvalues (including both prvalues and xvalues), while the lvalue reference overload binds to lvalues

By std::move(rv); you cast rv - Lvalue to Rvalue reference, and operator= which takes Rvalue reference is called. Otherwise, Lvalue binds to Lvalue reference and vector is copied instead of being moved.

like image 72
rafix07 Avatar answered Oct 07 '22 01:10

rafix07