2013-06-28 15 views
6

Während ich las http://thbecker.net/articles/rvalue_references/section_01.html, bekam ich folgende schnippste.Genaue Differenz zwischen rvalue und lvalue

// lvalues: 
// 
int i = 42; 
i = 43; // ok, i is an lvalue 
int& foo(); 
foo() = 42; // ok, foo() is an lvalue 
int* p1 = &foo(); // ok, foo() is an lvalue 

// rvalues: 
// 
int foobar(); 
int j = 0; 
j = foobar(); // ok, foobar() is an rvalue 
int* p2 = &foobar(); // error, cannot take the address of an rvalue 
j = 42; // ok, 42 is an rvalue 

Warum int * p2 = & foobar(); ist eine Fehleranweisung, während int * p1 = & foo(); ist kein Fehler. Wie später ist man lvalue, während der erste rvalue ist?

Vielen Dank im Voraus

+0

Ich glaube, Ihr letzter Satz hat es rückwärts –

Antwort

4

So haben wir zwei Funktionen:

int& foo(); 
int foobar(); 
  • foo ist eine Funktion der Rückkehr lvalue Verweis
  • foobar ist eine Funktion der Rückkehr int
int

Die Funktionsaufrufausdrücke:

foobar() 
foo() 

haben beide Typ int (Referenzen von Ausdrücken entfernt werden, so foo() hat Typ int und nicht lvalue-reference to int). Die beiden Ausdrücke haben unterschiedliche Wertekategorien:

  • foobar() ist ein prvalue (ein Funktionsaufruf zu einer Funktion eine Nicht-Referenz Rückkehr ist ein prvalue)
  • foo() ist ein L-Wert (ein Funktionsaufruf zu einer Funktion einer Rückkehr L-Wert-Referenz ist ein L-Wert)

Sie können nicht nehmen Sie die Adresse eines rvalue (a prvalue ist eine Art von R-Wert), so &foobar() ist nicht erlaubt.

Sie können die Adresse eines Lvalue so nehmen, dass &foo() zulässig ist.

+0

Warum ist es nicht möglich, die Adresse von foo nehmen? –

+0

@ ss7don: Du meinst den Ausdruck 'foo()'? Sie können die Adresse von 'foo()' nehmen. Lies die letzte Zeile meiner Antwort noch einmal. –

+0

Ich habe die Antwort akzeptiert, da es vernünftig aussieht. Ehrlich gesagt verstehe ich immer noch nicht den genauen Unterschied zwischen foo und foobar. Beides sind Funktionen. Aber wie man rvalue und ein anderes ist lvalue. –

6

Angenommen, wir haben den Beispielcode in C. Wird er kompiliert? Wie funktionieren die Konzepte von Lvalues ​​und Rvalues ​​in diesem Problem?

#define X 8 
int main(void) 
{ 
    ++X; // will this line compile? 
     return 0; 

} 

Das Konzept der lvalues ​​und rvalues ​​muss ein wenig, um den Code oben, und das Problem wird gebeten, um wirklich zu verstehen erklärt. Bevor wir fortfahren, sollten Sie beachten, dass die hier vorgestellte Definition von lvalues ​​und rvalues ​​nicht exakt ist, da selbst die C-Standards in der Definition eher vage sind.

Der Unterschied zwischen rvalues ​​und lvalues ​​

Ein Objekt ist ein Bereich des Speichers, der untersucht werden kann, aber nicht unbedingt modifiziert. Ein Lvalue ist ein Ausdruck, der sich auf ein solches Objekt bezieht. Der Begriff lvalue bezog sich ursprünglich auf Objekte, die auf der linken (also der 'l') Handseite eines Ausdrucks erscheinen. Diese Definition ist nicht mehr gültig, da jeder mit const qualifizierte Typ ebenfalls als L-Wert betrachtet wird. Er kann jedoch niemals auf der linken Seite einer Zuweisungsanweisung stehen, da er nicht geändert werden kann. Daher wurde der Begriff "modifizierbarer L-Wert" erstellt, um auf einen L-Wert Bezug zu nehmen, der modifiziert werden kann, und ein Konst-qualifizierter Typ fällt nicht in diese Kategorie.

Ein rvalue ist ein beliebiger Ausdruck, der einen Wert hat, dem jedoch kein Wert zugewiesen werden kann. Man könnte auch sagen, dass ein R-Wert ein beliebiger Ausdruck ist, der kein L-Wert ist.Ein Beispiel für einen rvalue wäre eine wörtliche Konstante - etwa "8" oder "3.14". Also, der Wert '8' im obigen Code ist eindeutig ein rvalue.

Mit unserem Verständnis von lvalues ​​und rvalues ​​die Frage zu beantworten

Nun wollen wir versuchen, das Problem zu lösen. Streng genommen muss der Operand des Präfix- (oder Postfix-) Inkrementoperators ein modifizierbarer L-Wert sein. Also, was ist der Operand des Präfix-Inkrementoperators in unserem obigen Code?

Da X ein Makro ist, wird die obige Anweisung nach der Ausführung des Präprozessors auf "++ 8" erweitert. Dies bedeutet, dass "8" der Operand des Präfix-Inkrementoperators ist. Und da 8 ein rvalue ist, kann es nicht als Argument für "++" verwendet werden. Dies bedeutet wiederum, dass der obige Code nicht kompiliert wird.

+1

Sehr nett, aber warum mit diesem Beispiel zu beschäftigen? Ich sehe nicht, wie eine Quizfrage beim Verständnis dieses Problems helfen kann. – SChepurin

Verwandte Themen