Why can't C ++ lvalue objects be tied to rvalue links (&&)?

The idea of ​​move semantics is that you can capture everything from another temporary object (with a link to the rvalue link) and save that “everything” in your object. This helps to avoid deep copying, where a single build of things is enough, so you build objects in the rvalue object, and then just transfer them to your long live object.

Why does C ++ not allow lvalue objects to be attached to rvalue links? Both allow me to modify the reference object, so for me there is no difference in accessing the internals of the reference object.

The only reason I can guess is the overload of ambiguity functions.

+5
source share
2 answers

But why does C ++ not allow you to bind lvalue objects to rvalue values?

Assuming you mean "Why C ++ doesn't allow you to bind rvalue references to lvalue objects": this is so. It is simply not automatic, so you should use std::move to make it explicit.

Why? Because otherwise, a harmless function call may unexpectedly destroy what you did not expect from it:

 Class object(much,state,many,members,wow); looks_safe_to_me(object); // oh no, it destructively copied my object! 

vs.

 Class object(much,state,many,members,wow); obviously_destructive(std::move(object)); // same result, but now the destruction is explicit and expected 

A note on destructive copying: why I say destructively and destruction above, I do not mean that the destructor object ends its life: its internal state simply moved to a new instance. It is still a valid object, but no longer contains the same expensive state in which it was used.


A note on terminology: see if we can eliminate the inaccurate use of lvalue, rvalue, etc. above.

Quote from cppreference for posterity:

  • a lvalue

    an expression that has an identity and cannot be moved out of.

    So, there is no such thing as an lvalue object, but there is an object that is locally called (or referred to) by the lvalue expression

  • a rvalue

    an expression that is either a prvalue value or an x ​​value. It can be transferred. He may or may not have an identity.

    • The prvalue value (pure rvalue) is roughly an expression related to an unnamed temporary object: we cannot convert our lvalue expression to one of these IIUCs.

    • xvalue value (expiring value)

      an expression that has an identity and can be transferred from.

      which explicitly includes the result of std::move

So what actually happens:

  • object exists
  • the object is identified locally using the lvalue expression, which cannot be transferred from (to protect us from unexpected side effects)
  • std::move gives an xvalue expression (which can be moved), referring to the same object as the lvalue expression
  • this means that objects, such as variables (called lvalue expressions), cannot be moved implicitly and must be moved explicitly from an explicit xvalue expression such as std::move .
  • anonymous temporary files are probably already mentioned by prvalue expressions and can be moved implicitly
+15
source

Essentially, you need a mechanism to distinguish between values ​​that can be transferred and those that cannot be transferred from (for example, you need a copy).

Providing both r values ​​and lvalues ​​is bound to an lvalue reference makes it impossible.

Therefore, values ​​bound to an rvalue link can be moved from (not necessarily always moved, but allowed), and lvalues ​​can be bound to lvalue links and cannot be moved from.

std::move to enable casting between categories of values ​​(up to the value of r) to enable transition.

Note; Constant references ( const T& ) can be attached to both rvalues ​​(temporary) and lvalues, since the mentioned object cannot change (it is marked as const , so there can be no movement in any case).

There is some story (back to the early days of C ++) why temporary objects cannot be tied to non-constant lvalue references to start with ... the detail is blurry, but there were several considerations that changing the temporary doesn't make sense , since it's all equally destroy at the end of the current statement. In addition, you can be lulled in the sense that you changed the lvalue when you are where you really are not - the semantics of the code could / would be incorrect and would be an error. There are additional reasons related to addresses, literals, etc. This was before displacement, and the semantics of this hardened and is one of the motivations for displacement and its semantics.

+3
source

Source: https://habr.com/ru/post/1243941/


All Articles