Is it useless to declare a local variable as rvalue-reference, e.g. T&& r = move(v)?
Asked Answered
P

2

33

Could you guys give me an illustrative example under certain circumstance to prove the following statements are useful and necessary?

AnyTypeMovable   v;
AnyTypeMovable&& r = move(v);
Primp answered 12/9, 2013 at 13:57 Comment(5)
I'd say it's rather useless since r is now an lvalue (it has a name!), and you need std::move(r) anyway to make it an rvalue.Bacchant
Fun fact: v doesn't need to be movable.Nyssa
Fun fact: there is no move happening in this code.Grekin
I wouldn't say it's 100% useless, you could use it to tell people reading the code next that this variable is a temporary and it will be moved, though I suppose in general it's easy to spot when std::move is called anywayDwyer
@DavidRodríguez-dribeas Devils AdvocateDwyer
J
16

No, AnyTypeMovable&& r = move(v); here is not useful at all.

Consider the following code:

#include <iostream>
#include <vector>

class MyMovableType
{
        int i;
public:
        MyMovableType(int val): i(val){}
        MyMovableType(MyMovableType&& r) { this->i = r.i; r.i = -1; }
        MyMovableType(const MyMovableType& r){ this->i = r.i; }
        int getVal(){ return i; }
};

int main()
{
        std::vector<MyMovableType> vec;
        MyMovableType a(10);
        MyMovableType&& aa = std::move(a);

        vec.push_back(aa);

        std::cout << a.getVal() << std::endl;

        return 0;

}

As aa is an l-value (as noted by R. Martinho Fernandes, and also by Xeo - a named rvalue-reference is an lvalue), this will print 10 indicating that moving has not been performed (nor in the assignment, nor in the push_back call), so you still need to std::move it to the push_back method, as in this case:

#include <iostream>
#include <vector>

class MyMovableType
{
        int i;
public:
        MyMovableType(int val): i(val){}
        MyMovableType(MyMovableType&& r) { this->i = r.i; r.i = -1; }
        MyMovableType(const MyMovableType& r){ this->i = r.i; }
        int getVal(){ return i; }
};

int main()
{
        std::vector<MyMovableType> vec;
        MyMovableType a(10);
        MyMovableType&& aa = std::move(a);

        vec.push_back(std::move(aa));

        std::cout << a.getVal() << std::endl;

        return 0;

}

move will be performed, so the printout will be -1. So, despite the fact that you're passing aa to the push_back, you still need to pass it via std::move.

Juniejunieta answered 12/9, 2013 at 14:16 Comment(4)
So in this context std::string&& is just the same as std::string&? Is this how the standart defines it?Barden
@Haatschii: Yes, a named rvalue-references is an lvalue.Nyssa
The first test is inconclusive, btw. Moving a std::string doesn't require the original string to be left in any particular state. It only has to be valid, and it's perfectly fine for it to have the same original value.Bacchant
@R.MartinhoFernandes You're right, I will write a simple class instead.Juniejunieta
S
1

Note that, Named rvalue is lvalue. So you should use std::forward.

#include <iostream>
#include <vector>

class MyMovableType
{
        int i;
public:
        MyMovableType(int val)  noexcept   : i(val){}
        MyMovableType(MyMovableType&& r) noexcept { this->i = r.i; r.i = -1; }
        MyMovableType(const MyMovableType& r) noexcept{ this->i = r.i; }
        int getVal()const noexcept{ return i; }
};

int main()
{
        std::vector<MyMovableType> vec;
        MyMovableType a(10);
        MyMovableType&& aa = std::move(a);

        vec.push_back( std::forward<decltype(a)>(aa) );

        std::cout << a.getVal() << std::endl; // -1 printed.

        return 0;

}
Serrulate answered 12/9, 2013 at 16:51 Comment(2)
If I understand right, the std::forward call here will do the same thing that std::move would do (that is, it will finally move the aa that was not yet moved by the preceding call to std::move)--yet nonetheless std::forward should not be used here, because its purpose is to "forward" type information that is unknown in the scope of the std::forward call, and said info is NOT unknown here (i.e., we know all about the type of aa). (NB - I have only just learned about this stuff and am mainly parroting Scott Myers: scottmeyers.blogspot.com/2012/11/… )Gloriane
yeah, keep std::forward for proper argument forwarding, not move semanticLateshalatest

© 2022 - 2024 — McMap. All rights reserved.