31

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);
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
xmllmx
  • 39,765
  • 26
  • 162
  • 323

2 Answers2

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.

Community
  • 1
  • 1
Nemanja Boric
  • 21,627
  • 6
  • 67
  • 91
  • 3
    So in this context `std::string&&` is just the same as `std::string&`? Is this how the standart defines it? – Haatschii Sep 12 '13 at 14:29
  • 4
    @Haatschii: Yes, a named rvalue-references is an lvalue. – Xeo Sep 12 '13 at 14:29
  • 5
    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. – R. Martinho Fernandes Sep 12 '13 at 14:33
  • @R.MartinhoFernandes You're right, I will write a simple class instead. – Nemanja Boric Sep 12 '13 at 14:34
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;

}
Khurshid Normuradov
  • 1,564
  • 1
  • 13
  • 20
  • 4
    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: http://scottmeyers.blogspot.com/2012/11/on-superfluousness-of-stdmove.html ) – mjwach May 10 '15 at 04:18
  • yeah, keep std::forward for proper argument forwarding, not move semantic – Julien__ Apr 14 '16 at 18:24