Work encountered a reference to the issue of temporary variables, after two days of study, private thought: not only to understand the problem, but also some of their own unique ideas. Here's a simple example to dedicate your learning process and understanding to everyone, and if you have any questions, please do not hesitate to correct it. code************************* classDog{ Public:Dog(){}Virtual~Dog(){}};voidnonconstreference(Dog&Dog){//tell the dog to does something here}voidtestnonconstreference(){nonconstreference(Dog());} VS, Level4 (/w4) ************************* warning C4239:nonstandard extension used: ' Argument ': Conversion from ' dog ' to ' dog & ' *************************GCC, c++11*************************--------------Build:debug in Test (compiler:gnu GCC compiler)---------------Mingw32-g++.exe-wall-fexceptions-g-std=c++11-c G:\MyBackup\code\CodeBlock\Test\main.cpp-o obj\debug\main.og:\ mybackup\code\codeblock\test\main.cpp:in function ' void testnonconstreference () ':G:\mybackup\code\codeblock\test\main.cpp:18:29:error:invalid Initialization ofnon-const Reference of type' dog& ' from anrvalue of type' Dog 'g:\mybackup\code\codeblock\test\main.cpp:11:6: error:in passing argument 1 of ' void Nonconstreference (Dog&) ' Process terminated with status 1 (0 minute (s), 0 second (s))2 Error (s), 0 warning (s) (0 minute (s), 0 second (s)) Lvalue, Xvalue, Prvalue general definition ************************* First Lvalue, rvalue are for expressions Any expression can be categorized as follows: Lvalue refers to a function or object. For example:
- E is a pointer, then *e is Lvalue
- The return value of a function is an lvalue reference, and its return value is Lvalue. For example int& foo ();
Xvalue refers to an object, but unlike Lvalue, the object is about to die. Prvalue refers to a temporary object, a child object of a temporary object, or a value that is not assigned to any object. For example:
- The return value of a function is the usual type, and its return value is rvalue. For example, int foo ();
- There are no values assigned to any object. such as 5.3,true.
Lvalue, Xvalue, Prvalue distinguish ************************* Description: This part comes from C + + programming LANGUAGE 4TH Edtion. There is the properties that matter for a object when it comes to addressing, copying, and moving:
•Has identity: The program have the name of, pointer to, or reference to the object so it's possible to determine if both objects a Re the same, whether the value of the object has changed, etc.
•Movable: The object is moved from (i.e., we is allowed to move it value to another location and leave the object in a valid But unspecified state, rather than copying;).
It turns out this three of the four possible combinations of those the properties is needed to precisely describe the C + + Language rules (we have no need for objects that does not have the identity and
cannot be moved). Using "M for movable" and "I for have identity, ' we can represent this classification of expressions graphically:
So, a classical lvalue was something that have identity and cannot be moved (because we could examine it after a move), and A classical rvalue is anything this we are allowed to move from.
ISO IEC 14882 20118.5.3 ReferencesThe ISO document uses CVS to represent the const volatile modifier. And suppose we use a way to assign values: cv1 T1 dest = cv2 T2 src; for example: int src = 123;const int& dest = src; void function (const int& dest) {};function (SRC); The ISO document first gives two concepts: reference-related, reference-compatible. Given Types "CV1T1 "and"Cv2T2, ""CV1T1 "isreference-relatedTo "Cv2T2 "If
- T1 is the same type as T2, or
- T1 is a base class of T2.
“CV1T1 "isreference-compatibleWith "Cv2T2 "If
- T1 is reference-related to T2 and
- CV1 is the same cv-qualification as, or greater cv-qualification than, cv2.
Description: CV1 >= cv2: const > No modifier, const volatile > Const,etc. Parse once assignment: cv1 T1 dest = cv2 T2 src; The legal use of the following 4 steps: 1. If Dest is a lvalue reference, at the same time: 1.1 If SRC is an lvalue (not a bit-filed) and Cv1 T1 is reference-compatible with Cv2 T2 ; 1.2 If T2 is a class type (class, struct, Union, etc), even if CV1 T1is notReference-compatible with Cv2 T2, as long as Cv2 T2 can be converted to an lvalue of the cv3 T3 type (SRC1), if Cv1 T1 is reference-compatible with cv3 T3; then des T fix it to SRC, or src1. 2. If Cv2 T2 SRC does not meet 1.1,1.2, then CV1 should be a lvalue reference definition that contains a const, otherwise it would be a rvalue reference. At this point if the Cv2 T2 satisfies the following conditions: 2.1 If SRC is a xvalue, a prvalue of class type, an array prvalue or a function that returns an Lvalue, and Cv1 T1 is reference-compatible with Cv2 T2 ; 2.2 If Cv2 T2 is of class type, even CV1 T1is notReference-compatible with Cv2 T2, as long as Cv2 T2 can be converted to a 2.1 specified value of the CV3 T3 type, assuming it is src1; then dest will help to SRC, or src1. 3. If Cv2 T2 SRC does not satisfy the 2.1,2.2, then the compiler creates a temporary variable for SRC. 3.1 The condition for creating this temporary variable is: CV1 T1 is reference-relatedWith Cv2 T2, and Cv1 >= cv2; 4. If Cv2 T2 SRC does not meet all of the above conditions, then CV1 T1 should be a rvalue reference. At this point, if Cv2 T2 is a lvalue, the compiler should hold the wrong. Reference matching (filtering) process ************************* ************************************** Here are some examples of **************************************------------------------------- Can be processed by rule 1-------------------------------------------------Double d = 2.0;
double& rd = D;//d, is an lvalue, and the CV1 equals CV2, 1.1 capable of handling Const double& RCD = D;//D, is an lvalue,//The CV1 >= cv2:const > No modifier, 1.1 capable of handling struct A {};
struct B:A { operator int& ();} b;
a& RA = b;//b, has A class type:struct;//CV1 is reference related with CV2, and Ra is the base class of the b,1.2 capable of handling const a& RCA = B;//b, has A class type, struct;//CV1 is reference related with Cv2, RA is the base class of the B;//The CV1 >= cv2:const > No modifier, 1.2 capable of handling int& ir = b ();//b (), has a class type:struct//it can converted to an lvalue of the Int&: operator int& ()//CV1 = = CV2:CV modifier is empty, 1.2 can handle ------------------------------does not conform to rule 1 and is handled by rule 2-----------------------------------------
extern B f ();
Const a& RCA2 = f ();//F () The return value is a rvalue of a class type,
//The CV1 >= cv2:const > No modifier, 2.1 capable of handling
struct X {
operator B ();
operator int& ();
} x;
Const a& r = x;//x is a class-type//R and X are not reference-compatible//X returns a class type of Prvalue through operator B (), TMPBthe relationship between R and TMPB satisfies 2.1 of the conditions, 2.2 can handle the-----------------------does not conform to rule 1 and does not conform to rule 2 and is handled by rule 3--------------------------- const double& RCD2 = 2;//2, not a lvalue/xvalue/class type prvalue/function returns the left value, etc. //Create a temporary variable 2.0,3 can handle --------does not conform to rule 1, also does not conform to rule 2, does not conform to rule 3, is handled by rule 4---------------------- Double d2 = 1.0;
double&& rrd2 = d2;//Rrd2 is a rvalue reference and cannot be assigned with Lvalue. 4 able to handle -----------------------------------------Some other examples------------------------------------------------------------- const volatile int CVI = 1;
const int& r2 = CVI;//error, in thisexample, the CV1 <= cv2, which violate the 1.1 ************************* back to our example ************************* classDog{ Public:Dog(){}Virtual~Dog(){}};void nonconstreference(Dog&Dog){//tell the dog to does something here}voidtestnonconstreference(){nonconstreference(Dog()); }nonconstreference(Dog()) Call to create a class type of prvalue on the stack. According to the ISO document, it cannot be accepted in rule 1, it can only be processed by rule 2. Rule 2 Requirementsnonconstreference(Dog&Dog)the dog & dog must be a const dog & dog. and here is obviously not, so hold the wrong. What did the compiler do for us? Semantic Analysis ***************************** The compiler, in strict accordance with the design of the C + + language, performs a semantic check:
- The goal is a lvalue reference, then can not give me a rvalue.
- or set the target to a const lvalue reference.
If a parameter is passed in as a non-const reference, the C + + compiler thinks that the program modifies the value in the function and wants the modified value. But if you pass in a temporary variable as a non-const reference parameter, the program does not have the opportunity to continue accessing such a variable, making it meaningless to modify a temporary variable. The C + + compiler thus joins the semantic limit of temporary variables that cannot be used as non-const references, and is intended to limit the potential errors of this very compliant usage. Finish *******************************************
The ultimate parsing of c++11 referencing temporary variables