Left value. Right value. Reference. const reference

Source: Internet
Author: User

// The following is my personal understanding. If you have any errors, please let us know. Thank you very much. <Br/> # include <string> <br/> # include <iostream> <br/> using namespace STD; <br/> string one ("cute "); // non-const lvalue <br/> const string two ("fluffy"); // const lvalue <br/> string three () // non-const rvalue <br/>{< br/> return "kittens"; <br/>}< br/> const string four () // const rvalue <br/>{< br/> return "are an essential part of a healthy diet "; <br/>}< br/> string & five (string & I) <br/>{< br/> S TD: cout <I; <br/> I = "Haha"; <br/> return I; <br/>}< br/> void six (const string & I) <br/>{< br/>}< br/> void six (string & I) <br/>{< br/>}< br/> // 1. The left and right values are for expressions rather than objects. <Br/> // 2. An expression is composed of one or more operands by operators. The simplest expression only contains one nominal value or variable. <Br/> // I think a function call is also an expression, because the operator operates on the operand by using a function call. <Br/> // 3. Each expression generates a result, which can be divided into the left and right values. This is a complete set, and there are only two possibilities. <Br/> // 4. What is a statement and a statement is an expression plus sign. <Br/> // 5. lvalue indicates the persistent objects that exist after a single expression ends. For example, OBJ, * PTR, PRT [Index], ++ X are all lvalues. <Br/> // 6. The result returned by an operator expression is a persistent object after the expression ends. <br/> // 7, if the expression ends with a semicolon, the result of the expression will not disappear. <Br/> // 8. Another way to cultivate the intuition of judging whether an expression is lvalue or not is to ask yourself, "can I retrieve the address of an expression? ", <Br/> // 9. If yes, It is an lvalue. If no, It is an rvalue. <Br/> int main () <br/> {<br/> 345; // 345 is a nominal value, so it is an expression, adding a semicolon constitutes a statement, which is legal. <Br/> // The literal value cannot be an address, so the result of the literal expression is a right value. <Br/> string I = "hehe"; <br/> I; // I is a variable, all of which are also an expression. A semicolon is added to form a statement. <Br/> // the value of this expression is the object I, which continues to exist after the semicolon and can also be retrieved. Therefore, this expression is a left value. <Br/> three (); // three () is an expression. The result of this expression is a temporary object of the string type. This object disappears after the semicolon, <br/> // I don't know if it can be accessed. It is the right value. <Br/> // do you know if it is the right value, it cannot be accessed, or is it true that both 8 and 5 are necessary, the right value may not always be satisfied. <br/> // either the right value or the full set is satisfied, and the non-left value is the right value. <Br/> four (); // four () is an expression. The result of this expression is a temporary object of the const string type, which disappears after the semicolon, <br/> // This is the right const value. <Br/> five (I); // five (I) is an expression. The function call expression is a left value only when a reference is returned by a function call. <Br/> // type & can be bound to non-const lvalue. For example, in this example, you can use this reference to read and modify the original value ), <br/> // but cannot be bound to the const lvalue, because it violates the const correctness. <br/> // It cannot be bound to the non-const rvalue, this operation is extremely dangerous. You can use this reference to modify the temporary object, but the temporary object has long existed. <br/> // This will cause hard-to-catch and annoying bugs, therefore, C ++ wisely prohibits this. <Br/> five (three (); // type & bind to non-const rvalue. Isn't this true? vs2008 can be compiled and run without any problems, server. <Br/> // change the compilation option to/W4 and generate warning c4239, msdn: This type conversion is not allowed by the C ++ standard, <br/> // but it is permitted here as an extension. this warning is always followed by at least one line of <br/> // explanation describing the language rule being violated. <br/> // c4239.cpp <br/> // compile with:/W4/C <br/> // struct c {<br/> // C () {}< br/> // }; <br/> // void func (void) {<br/> // C & rc = C (); // c4239, the result of the C () expression is the standard non-const rvalue, anonymous object, I don't know how to call temporary variables, right, however, <br/> // non-const rvalue should be the correct name <br/> // const C & RC2 = C (); // OK <br/> // RC2; <br/> //} <br/> // There are actually four types of expressions, non-const lvalue, non-const rvalue, const lvalue, const rvalue <br/> // type & can only be bound to non-const lvalue, but cannot be bound to const lvalue or const rvalue. Obviously, because they are const and type & No. <Br/> // The non-const rvalue cannot be bound as described above. <Br/> // For the reason, C ++ considers that defining a non-const function is an attempt to modify the input real parameter, if you do not want to <br/> // modify it, why not define a function that accepts the const object, that is, define it as const type &. But first, you define the function as type &, c ++ considers <br/> // The non-const rvalue of the two non-const types as dangerous, therefore, C ++ prohibits you from doing this because of the life cycle of non-cnost rvalue. <Br/> // summary type & can only accept non-const lvalue of one of the four types. In two cases, one is to define the reference directly, and the other is to define the five. <Br/> six (I); // The six function has an overloaded version. One accepts const string & and the other accepts string &. When the real parameter is a non-const, <br/> // I, for example, in this example, <br/> // non-const version is called, which is matched first, for const type & it can accept each of the four types of objects, there is nothing to say about the two types of lvalue, <br/> // for the two types of rvalue, it will form a temporary variable, and then associate the reference with this temporary variable, and I think this is not a temporary variable, it is a <br/> // temporary local variable, because after the semicolon, this temporary variable should not be in its life cycle, because the reference still needs to have associated memory, reference is the left value, total <br/> // you can retrieve the address. It is not possible to obtain a temporary variable. Therefore, I call this variable a temporary local variable, it is temporary because the programmer cannot see it and says it is partial. <br/> // It is because its life cycle should This starts from the definition to the return at the end of the function. This is also the case in C ++ primer. It is different from what I said. <br/> // double dval = 3.14; <br/> // cosnt Int & I = dval; // The book says the compiler will convert the code into the following code form <br/> // double dval = 3.14; <br/> // int temp = dval; <br/> // const Int & I = temp; <br/> return 0; <br/>}

Below are some Reprints

C ++ 03 standard section 3.10/1: "Each expression is either an lvalue or an rvalue. "Remember that lvalue and rvalue are for expressions, not objects.

Lvalue refers to the persistent objects that exist after the end of a single expression. For example, OBJ, * PTR, PRT [Index], ++ X are all lvalues.

Rvalue refers to the temporary objects that no longer exist at the end of the expression (at the semicolon. For example: 1729, X + Y, STD: string ("meow"), and X ++ are both rvalues.

Note the differences between ++ X and X ++. When we write int x = 0;, X is an lvalue because it represents a persistent object. Expression ++ X is also an lvalue, which modifies the value of X, but still represents the original Persistent Object. However, the expression x ++ is an rvalue. It just copies the initial value of a persistent object, modifies the value of the Persistent object, and returns the copy, which is a temporary object. Both ++ X and X ++ increase by X, but ++ x returns the Persistent object itself, while X ++ returns the temporary copy. This is why ++ X is an lvalue while X ++ is
Rvalue. The difference between lvalue and rvalue lies not in what the expression does, but in what the expression represents (A Persistent object or a temporary product ).

Another way to cultivate the intuition of judging whether an expression is lvalue is to ask yourself, "can I access an expression? ", If possible, it is an lvalue; if not, it is an rvalue. For example: & OBJ, & * PTR, & PTR [Index], and & ++ X are both legal (even if some of them are stupid), and & 1729, & (x + y), & STD: string ("meow"), and & X ++ are invalid. Why does this method work? Because the address fetch operation requires that its "operand must be an lvalue" (see C ++ 03 5.3.1/2 ). Why is there such a rule? Because it is okay to retrieve the address of a persistent object, but it is extremely dangerous to retrieve the address of a temporary object, because the temporary object will soon be destroyed: just as you have a pointer to an object, the object is released, but you are still using the pointer. The ghost knows what the Pointer Points to at this time ).

The preceding example does not consider Operator overloading. It is just a common function call syntax. "A function call is an lvalue only when it returns a reference" (see C ++ 03 5.2.2/10 ). Therefore, the given statement vercor <int> V (10,172 9);, V [0] is an lvalue, because the operator [] () returns Int & (and & V [0] is valid and available); and the given statements string S ("foo"); and string T ("bar ");, S + T is an rvalue, because the operator + () returns string (and & (S + T)
Is invalid ).

Both lvalue and rvalue have modifiable (non-const) and Const. For example:

String one ("cute ");

Const string two ("fluffy ");

String three () {return "kittens ";}

Const string four () {return "are an essential part of a healthy diet ";}

One; // modifiable lvalue

Two; // const lvalue

Three (); // modifiable rvalue

Four (); // const rvalue

Type & can be bound to a very large number of lvalues (this reference can be used to read and modify the original value), but cannot be bound to the const lvalue, because it will violate the const correctness; it cannot be bound to a very large number of rvalues. This is extremely dangerous. You can use this reference to modify the temporary object, but the temporary object has long existed, this will lead to hard-to-catch and annoying bugs, so c ++ wisely prohibits this. (I would like to add: VC has an evil extension that allows this to be cool, but if you add the parameter/W4 during compilation, the compiler usually prompts "An evil extension is activated "). It cannot be bound to const ravlue, because it would be twice as bad. (Careful readers should note that I didn't talk about template parameter derivation here ).

Const type & can be bound to: very large numbers of lvalues, const lvalues, very large numbers of rvalues and const values. (Then you can use this reference to observe them)

The reference is named, so a reference bound to rvalue itself is an lvalue (yes! Is L ). (Because only the const reference can be bound to rvalue, It is a const lvalue ). This is confusing (not clear) and will be harder to understand later, so I will explain it further. Given the void observe (const string & Str) function, in the implementation of the observe ()'s, STR is a const lvalue, In the observe () the address that can be retrieved and used before the return. This even if we pass an rvalue
Parameter to call observe () is also true, just like three () and four () above (). You can also call observe ("Purr") to construct a temporary string and bind STR to that temporary string. The returned objects of three () and foure () are not named, so they are rvalue, but in observe (), STR is named, so it is an lvalue. As I mentioned earlier, "lvalue and rvalue are for expressions, not objects ". Of course, because STR can be bound to a temporary object that will soon be destroyed
After the observe () is returned, we should not save the address of this temporary object anywhere.

Have you ever retrieved a const reference bound to rvalue? Of course you have! Every time you write a copy assignment operator with a self-assigned Value Check: Foo & operator = (const Foo & Other), if (this! = & Other) {copy struff;}; or copy and assign values from a temporary variable, such as: Foo make_foo (); Foo F; F = make_foo, you did this.

At this time, you may ask, "What is the difference between rvalues and const rvalues? I cannot bind type & to a non-constant rvalue or modify rvalue by assigning values. Can I modify them? "This is a good question! In C ++ 98/03, There are some minor differences between the two: Non-constrvalues can call the non-const member function. C ++ does not want you to accidentally modify the temporary object, but directly calls the non-const member function on non-const rvalues. This is obvious, so this is allowed. In
In C ++ 0x, the answer has changed significantly, and it can be used to implement moving semantics.

Congratulations! You already have the so-called "lvalue/rvalue View", so that you can determine whether an expression is lvalue or rvalue at a glance. Coupled with your original understanding of const, you can fully understand why the given statement void mutate (string & ref) and the previous variable definition, mutate (one) is legal, mutate (two), mutate (three (), mutate (four (), and mutate ("Purr") are invalid. If you are a C ++ 98/03 programmer, you can tell which of these calls are legal and which are illegal. It is your "Instinct instinct ", instead of your compiler, tell you
Mutate (three () is fake. Your new understanding of lvalue/rvalue gives you a clear understanding of why three () is an rvalue and why a mass reference cannot be bound to the right value. Do you know these are useful? It is useful for language lawyers, but not for common programmers. After all, if you don't understand everything about lvalues and rvalues, you have to understand this far away. But the point is: Compared with C ++ 98/03, lvalue and rvalue in C ++ 0x have a broader and stronger meaning (especially to determine whether the expression is modifiable/const ).
). To effectively use C ++ 0x, you also need to have an understanding of lvalue/rvalue. Now that everything is ready, we can move on.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.