Search code examples
c++c++11movervalue-referencervalue

Why use std::forward rather than std::move for data member in rvalue reference constructor's initialization list?


I have read these materials:

What's the difference between std::move and std::forward

std::move Vs std::forward

this answer is very close to my question, but one is setImage, the other is rvalue reference constructor, so I'm afraid something subtle exists.

Forward

class ClassRoom
{
private:
    vector<string> students;

public:
    ClassRoom(vector<string>&& theStudents)
        :students{std::forward<vector<string>>(theStudents)}
    {
    }
}

Move

class ClassRoom
{
private:
    vector<string> students;

public:
    ClassRoom(vector<string>&& theStudents)
        :students{std::move(theStudents)}
    {
    }
}

Someone told me forward is the right method here because one of the usages of forward is to pass rvalue reference variable to others and guarantee not use it again. but I can't figure out why not to use move here and is what he said right?


Solution

  • In this example, both std::move and std::forward do the same thing.

    This is different if you change the example to a deduced type, e.g.

    template<typename Arg>
    ClassRoom(Arg&& theStudents)
        :students{std::forward<Arg>(theStudents)}
    {
    }  
    

    v.s.

    template<typename Arg>
    ClassRoom(Arg&& theStudents)
        :students{std::move(theStudents)}
    {
    }
    

    Then:

    vector<string> local_students = /* ... */;
    ClassRoom cr(local_students) 
    

    Arg deduces to vector<string>&, which means different things happen

    Forward:

    forward<vector<string>&> passes along the lvalue-reference, so the overload of vector::vector chosen is the copy constructor, local_students is unaffected

    Move:

    move<vector<string>&> casts the lvalue-reference to rvalue-reference, so the overload of vector::vector chosen is the move constructor, local_students is now in the moved-from state