1

I have a class like this:

class Widget
{
public:
    Widget(A const& a) { /* do something */ }
    Widget(A&& a) { /* do something */ }
};

Which I can use like this:

A a{};
Widget widget{a};

If I came to the conclusion that I don't need a any longer, I could call:

Widget{std::move(a)};

But now what if I needed an A object only for the construction of widget? Would I do this:

Widget widget{A{}};

or

Widget widget{std::move(A{})}; 
hgiesel
  • 5,430
  • 2
  • 29
  • 56
  • 2
    I can't see any "temporary lvalue". `A{}` is an rvalue, so it overload resolution will pick up the move constructor. – juanchopanza Mar 10 '16 at 14:57
  • I think you meant to write `Widget widget{std::move(a)};` in the *or* case. – nwp Mar 10 '16 at 15:00
  • 1
    Then how come `A{} = A{};` is a valid expression? – hgiesel Mar 10 '16 at 15:00
  • Why wouldn't it? Do you think an rvalue cannot appear on the left side of an equation and because `A{} = A{}` is valid that must mean that `A{}` is not an rvalue? In that case forget about rvalue and lvalue in the sense of left and right of an assignment, that just doesn't hold in C++. – nwp Mar 10 '16 at 15:03
  • @hgiesel: This being C++, it wouldn't surprise me were that to turn out to be a declaration :P – Lightness Races in Orbit Mar 10 '16 at 15:03
  • @nwp: `int(42) = 43;` "error: lvalue required as left operand of assignment" Whether or not it applies here, such a rule _does_ exist. – Lightness Races in Orbit Mar 10 '16 at 15:04
  • In fact, this is interesting: `int{42} = 43;` "error: using temporary as lvalue" heh. Anyway, I think it only works because `A` isn't a built-in. – Lightness Races in Orbit Mar 10 '16 at 15:05
  • @BarryTheHatchet yes you can call non const methods on rvalue objects, `operator=` is not an exception – Slava Mar 10 '16 at 15:06
  • @nwp exactly that, I know lvalues needn't always be on the lhs, but I thought you couldn't assign rvalues – hgiesel Mar 10 '16 at 15:07
  • @hgiesel: You can't assign to rvalues of built-in types (don't forget the "to" in that sentence). But `A` is a class so the rules are substantially more relaxed. – Lightness Races in Orbit Mar 10 '16 at 15:07
  • 1
    As far as why `A{} = A{};` works see this: http://stackoverflow.com/questions/10897799/temporary-objects-when-are-they-created-how-do-you-recognise-them-in-code – NathanOliver Mar 10 '16 at 15:07
  • @BarryTheHatchet In all honesty `int{42} = 43;` should compile. There is no good reason to allow `Int{42} = 43;` and disallow `int{42} = 43;` besides *"nobody thought it was important enough to change it in the standard"*. – nwp Mar 10 '16 at 15:09
  • @nwp It is because built in types are not class types so they do not have member functions. – NathanOliver Mar 10 '16 at 15:10
  • @NathanOliver That doesn't make sense. It could still be allowed without member functions. It is a language design thing. – juanchopanza Mar 10 '16 at 15:12
  • @BarryTheHatchet techincally `A{} = A{};` can be treated as `A{}.operator=( A{} );` – Slava Mar 10 '16 at 15:16
  • @Slava: Yes, thank you, I am aware of that. – Lightness Races in Orbit Mar 10 '16 at 15:19

1 Answers1

4

A temporary is an rvalue; there are no "temporary lvalues". Widget widget{A{}}; will call Widget(A&& a) as A{} is a temporary. std::move is used when you have an lvalue and you want to make it an rvalue like you do with:

A a{};
Widget widget{std::move(a)};

Another reason to use it would be if you are in a function that takes an rvalue and you want to move it to the constructor. With the function

Widget foo(A&& a);

a is a lvalue in the body of the function. If you want to convert it back to an rvalue then you would need to use std::move like

Widget foo(A&& a)
{
    Widget widget{std::move(a)};
}
NathanOliver
  • 171,901
  • 28
  • 288
  • 402