8
struct Bar
{    
   Bar(std::string&& val)
    : m_Val(std::move(val)) {} // A

  Bar& operator=(Bar&& _other) { m_Val = std::move(_other.m_Val); }
  std::string m_Val;
}

struct Foo
{
  void Func1(Bar&& param)
  {
     Func2(std::move(param)) // B
  }

  void Func2(Bar&& param)
  {
     m_Bar = std::move(param); // C
  }

  Bar m_Bar;
};

void main()
{
   Foo f;
   std::string s = "some str";
   Bar b(std::move(s));
   f.Func1(std::move(b));
}

Give that you're calling move in main() to invoke the rvalue reference methods, is it necessary in lines A & B & C to repeat an additional call to move()? You already have the rvalue reference, so is it doing anything different in those lines with vs without?

I understand in Bar's operator= it's necessary because you're technically moving the m_Val rather than _other itself correct?

Note: Originally, I was incorrectly calling rvalue references as rvalue parameters. My apologies. I've corrected that to make the question easier to find and make clearer.

user99999991
  • 1,351
  • 3
  • 19
  • 43
  • 1
    I know you're probably doing this to make your point clear but note in your current example you don't need to write `Bar`'s move constructor at all. – Hatted Rooster Feb 28 '19 at 15:54
  • 7
    There's no such thing as "rvalue parameter". A *named* reference makes an *lvalue* expression (yes, even a rvalue reference is an lvalue). So, in order to make it into an xvalue again you need to apply `std::move` again. – AnT stands with Russia Feb 28 '19 at 15:54
  • @AnT I'm still confused about what your profile picture is supposed to be. – Hatted Rooster Feb 28 '19 at 15:58
  • @SombreroChicken - why is that? If I make the string in main, I don't need to move it? The whole thing, including String is contrived yeah, but my understanding is if I want to avoid copying it, I need to move it. – user99999991 Feb 28 '19 at 15:58
  • @AnT When I read about it in other SO's, theyre called "rvalue references". Sorry, I'll rename the question from Parameter to Reference. https://stackoverflow.com/questions/5481539/what-does-t-double-ampersand-mean-in-c11 – user99999991 Feb 28 '19 at 15:59
  • 1
    @user99999991 SombreroChicken means that for this `struct` in your example compiler will generate proper move ctor and move assignment operator implicitly so it is not necessary to define them manually here. – Slava Feb 28 '19 at 16:03
  • @Slava oh! thank you – user99999991 Feb 28 '19 at 16:04
  • @Sombrero Chicken: I don't remember how and why I came up with that idea for an avatar. But anyway: http://babepka.com/gallery/albums/ritacm/ritacm_maiden1.jpg – AnT stands with Russia Feb 28 '19 at 16:59
  • Note that you hard-coded _moving_ of object contents. Sometimes, it's better to use moving only for rvalue arguments and copying for lvalue arguments. This is what _perfect forwarding_ is for. That is, forwarding references combined with `std::forward`. – Daniel Langr Feb 28 '19 at 17:18

1 Answers1

12

Give that you're calling move in main() to invoke the rvalue parameter methods, is it necessary in lines A & B & C to repeat an additional call to move()?

Yes. What you call an rvalue parameter is actually an rvalue reference. Just like a lvalue reference, it is an lvalue in the scope that it is being used. That means you need to use move to cast it back into an rvalue so that it gets moved, instead of copied. Remember, if the object has a name, it is an lvalue.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • 1
    You'd improve this if you illustrated why. Basically, because the parameter could be used more than once in the body of the function. – Yakk - Adam Nevraumont Feb 28 '19 at 18:48
  • 1
    I did like you to make bold this; ***"..if the object has a name, it is an lvalue"*** ;. Because that's the key thing everyone should remember.. – WhiZTiM Mar 02 '19 at 09:47