-1

Modern C++ only adds one new type "xvalue"? The right reference returned by a function is xvalue, this is defined, just like the right reference in the parameters of a function, which can only bind to right value? These understandings correct? The questions and answers related to this topic handle this q from learner's perspective of view. Here I try to get to know this topic from the designer's perspective of view. For example, int b =3; int&& x = std::move(b); this return value of std::move is a xvalue and it can bind to rreference, this is the rule set by the designer. (reasonable and usable). The designer also can set a rule that xvalue needs to bind left reference,even this is not a good rule.

John
  • 1
  • 2
  • Do you have a concrete example? – tadman Jun 03 '18 at 00:56
  • My question is that are they defined or created by C++ designer from nothing? Of course, the designer must keep the the rules not conflict each other. For example, the right ref in function parameter list is a lvalue after binding to the caller parameter, this is deducted not defined. I have checked the answers on the internet, here just for verification of my understanding. – John Jun 03 '18 at 01:33
  • void fcn(int && a); int&& fcn2() { return 42;} fcn(32);//now a is lvalue – John Jun 03 '18 at 01:37
  • To put it simply, a xvalue is a lvalue (it refers to an object) that can be consumed because it's going away or because nobody cares about it anymore. – curiousguy Jun 03 '18 at 01:38
  • Wrong! Totally wrong!!!! xvalue belongs to both glvalue and rvalue! – John Jun 03 '18 at 02:02
  • @curiousguy I think you mean to say an xvalue is *like* an lvalue because both identify objects. xvalue and lvalue are mutually exclusive subcategories of expression. – aschepler Jun 03 '18 at 20:45
  • @aschepler An xvalue is a traditional C/C++ lvalue. I hate that lvalue was redefined. – curiousguy Jun 03 '18 at 22:26
  • @John Yes, and that terminology is a trainwreck (like much of C++ core innovation). A glvalue is just the good old lvalue: they have an identity, are not always produced locally and don't have well known dynamic type. OTOH the new rvalue isn't the good old rvalue, either. Complete breakage of old descriptions of C++. – curiousguy Jun 03 '18 at 22:35
  • 1
    @ curiousguy The glvalue and prvalue only make learners more confused. The really new thing is "&&", when it appears at function parameter list, it can bind to rvalue; when it appears function return result, it is an rvalue/xvalue can be bind to the former. And these rules are set by c++ designers. We can do nothing but follow. – John Jun 04 '18 at 00:57

1 Answers1

1

Be careful with terminology here. A function parameter or function return type might have/be an rvalue reference type, but is not an xvalue, because the term "xvalue" only applies to an expression.

Every expression is either an lvalue, an xvalue, or a prvalue. The most common sort of xvalue is an expression that calls a function that has an rvalue reference type as its return type. An expression that does a cast to an rvalue reference type is also an xvalue. There are a few other ways an expression can be an xvalue as well.

An rvalue reference is a type. A variable declared with an rvalue reference type can be initialized with either an xvalue or a prvalue, but not with an lvalue (unless via a user-defined conversion). Remember that the name of a variable declared as an rvalue reference is an lvalue, not an xvalue!

int n = 3;                          // 1
int&& r1 = static_cast<int&&>(n);   // 2
int&& r2 = std::move(r1);           // 3
int&& func(int&& arg);              // 4

The expressions in this code sample are:

  • 3 on line 1: a prvalue
  • n on line 2: an lvalue
  • static_cast<int&&>(n) on line 2: an xvalue
  • r1 on line 3: an lvalue
  • std::move(r1) on line 3: an xvalue

There are no expressions at all in line 4.

aschepler
  • 70,891
  • 9
  • 107
  • 161
  • My question is on line 2 and 3. These are newly defined in modern c++ , called "xvalue", correct? The designer also can avoid creating "xvalue", naming these line 2 and 3 as "lvalue". – John Jun 03 '18 at 01:52
  • "xvalue" has identity, the designer said it is consumable then it can be consumed. – John Jun 03 '18 at 02:07
  • right reference can be bound to prvalue, a "passive right value", not controlled by caller and xaluve, an "active right value" created by caller. – John Jun 03 '18 at 02:13
  • struct As { int i; }; As&& f(){ return As(); }; int main() { f().i; // The expression f().i belongs to the xvalue category, because As::i is a non-static data member of non-reference type, and the subexpression f() belongs to the xvlaue category. return 0; } – John Jun 03 '18 at 02:30
  • Is this using of right ref correct? f() returns xvalue, but this value will disappear after calling of f(). – John Jun 03 '18 at 02:32
  • 1
    @John "xvalue" applies only to expressions, and "rvalue reference" applies only to types and declarations. This might seem like nitpicking, but understanding it can help avoid some confusions. So in my example, `r1` in `int&& r1 =` is an rvalue reference but not an xvalue, because it's not an expression at all. – aschepler Jun 03 '18 at 20:26
  • 1
    @John An lvalue is the ordinary sort of expression that identifies some object. The term prvalue stands for "pure right value". Before C++17, a prvalue identified a temporary object which, is usually destroyed at the end of the full-expression containing the prvalue expression. As of C++17, a prvalue is not an object at all, just a representation of a way to initialize an object, and these materialize into temporary objects only when needed. An xvalue (expiring value) identifies an object like an lvalue, but can initialize an rvalue reference like a prvalue. – aschepler Jun 03 '18 at 20:32
  • 1
    @John An xvalue is normally used to specify that although the object might not identify a temporary object, it's okay for whatever uses the xvalue expression to "steal from" the object. When a function has a parameter with rvalue reference type, it can normally assume it's okay to steal from the referenced object, since it was either initialized from a prvalue (materializing a temporary object), or initialized from an xvalue, meaning someone explicitly said it's okay to steal from it. – aschepler Jun 03 '18 at 20:36
  • 1
    @John The `std::move` function does nothing but provide a nice way to build an xvalue expression from any other expression. Since `std::move` always returns an rvalue reference type, an expression like `std::move(var)` that calls `std::move` is an xvalue. So you use this to let C++ know that you don't need the old value of the object any more, and whatever function the result gets passed to may change that object. – aschepler Jun 03 '18 at 20:39
  • 1
    @John In your example, it's true that `f().i` is an xvalue. And the function `f` has a problem: it returns a reference to a temporary which has a lifetime only within the function body, so it's always invalid to attempt to use the result, even immediately. – aschepler Jun 03 '18 at 20:43
  • your example line 4. After the function is called, its return result is an xvalue. This statement correct? – John Jun 04 '18 at 08:36
  • @John The expression `func(2)` would be an xvalue. This is a feature of parsing the code, and has nothing to do with whether the function has been called, will be called, or is ever called at all. The expression's result is an object. – aschepler Jun 04 '18 at 22:57
  • int&& func(int&& arg); // 4 I mean this one. Not func(2), which means int&& func(int &&) is called. "There are no expressions at all in line 4." – John Jun 05 '18 at 01:30
  • @John I don't know what your question is. – aschepler Jun 05 '18 at 01:45