2

im reading this https://leanpub.com/cppmove (C++17 - The Complete Guide First Edition Nicolai M. Josuttisand) and regarding c++17 structured bindings and move semantics it gives the following example, where the moved from object ms is left intact:

MyStruct ms = { 42, "Jim" };   // struct has fields {int i, std::string s}
auto&& [v,n] = std::move(ms); 

// author says: the structured bindings v and n refer to an anonymous
// entity being an rvalue reference to ms, while ms still holds its value:

std::cout << "ms.s: " << ms.s << '\n'; // prints "Jim"

i have tested this, and at least in practical runs, this is true. but is that also generally how it should work? following the way the author gives his previous explanations about structured bindings, the above should be equivalent to

MyStruct ms = { 42, "Jim" };
auto&& e = std::move(ms); // anonymous compiler constructed entity "e"
/*aliasname*/ v = e.i; // v and n act as if e was constructed as
                       // above and v/n assigned to e.i/e.s as here
/*aliasname*/ n = e.s;

std::cout << "ms.s: " << ms.s << '\n'; // prints "Jim"

question:

so if this is a valid interpretation, would not auto&& e = std::move(ms) cause ms to immediately have its contents "moved"/"stolen"/"invalidated"? so that in both (equivalent?) variants above "Jim" is NOT (guaranteed to be) printed...?

clarification: i understand that std::move does not move anything but is a cast from an lvalue to an rvalue, but i would have thought that implied that at least you would not be able to count on the std::move-ed objects (here ms) contents being retained/available in subsequent uses

marked as dupe of What is std::move(), and when should it be used?. however, with ~300 upvotes, to that question, this answer: https://stackoverflow.com/a/27026280/11608725

The first thing to note is that std::move() doesn't actually move anything. It changes an expression from being an lvalue (such as a named variable) to being an xvalue. An xvalue tells the compiler:

You can plunder me, move anything I'm holding and use it elsewhere (since I'm going to be destroyed soon anyway)".

in other words, when you use std::move(x), you're allowing the compiler to cannibalize x

so i guess confusion is allowed:-P

please recommend a good book for ultradummies on c++17 and move semantics - this book-request most certainly is right-on-topic;-)

mrchance
  • 1,133
  • 8
  • 24
  • 5
    I think you have a misconception about `std::move`. In reality `std::move` neither moves nor constructs anything. There is no constructor call in `auto&& e = std::move(ms);`. – Lukas-T Sep 08 '20 at 20:10
  • @churill, yeah but ```move``` should it no be equivalent to stating that ms can no longer be counted on to retain its original content, is that not so? – mrchance Sep 08 '20 at 20:12
  • The `std::move` function doesnʼt actually move anything. The *move constructor* does, and `std::move` lets you call the move constructor. But in this case you arenʼt doing that; `auto&&` makes a reference. Iʼm pretty sure in both examples the call to `std::move` doesnʼt do anything useful. – Daniel H Sep 08 '20 at 20:14
  • 1
    `std::move` is just a cast. It casts whatever you give it to an xvalue so you can move from it if you give it to something that will actually move it, like a move constructor. – NathanOliver Sep 08 '20 at 20:15
  • @NathanOliver, yes but does that not imply a contract wrt subsequent use of ```ms```? that its content may have been moved, so dont count on it existing? – mrchance Sep 08 '20 at 20:20
  • @newbie Only if you give it to something that actually moves from `ms`. `auto&& e = std::move(ms);` is the same thing as `auto& e = ms;`. No object is created so nothing is moved. If you have `call_some_function(std::move(ms));` then you would be correct in not knowing if `ms` was moved from, but this is not what you have here. Here, you're just creating a reference. – NathanOliver Sep 08 '20 at 20:23

1 Answers1

2

would not auto&& e = std::move(ms) cause ms to immediately have its contents "moved"/"stolen"/"invalidated"?

std::move() only prepares ms to be moved, it doesn't outright move from it. That's why e is a reference to a MyStruct, not an actual MyStruct object.

einpoklum
  • 118,144
  • 57
  • 340
  • 684