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

2

6

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?

Spense answered 3/11, 2017 at 11:58 Comment(1)
The answer is: don't. Use std::forward when you want to perfect forward a deduced parameter (template/auto) - this may become equivalent to std::move (when the deduced parameter is an rvalue reference). Use std::move when you want to move from.Velarize
P
6

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

Paraplegia answered 3/11, 2017 at 12:9 Comment(4)
do you really need a variadic template here?Oppilate
It's a reasonable example of propagating all different arities of vector::vectorParaplegia
it's excessive in this example as it's based on original one with only one parameter, and so can confuse readers to think std::forward makes sense only with variadic templatesOppilate
@Gruffalo: that's a valid remark. When I was learning this stuff, I made this mistake.Velarize
O
1

I would use std::move here. std::forward is intended to forward universal references. There is no universal references in this case. Although in this example it'll be no difference, std::move is more concise and more self documenting.

Opinionative answered 3/11, 2017 at 12:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.