EINFÜHRUNG
ISOC ++ 11 (offiziell ISO / IEC 14882: 2011) ist die neueste Version des Standards der Programmiersprache C ++. Es enthält einige neue Funktionen und Konzepte, zum Beispiel:
- rWertreferenzen
- xvalue, glvalue, prvalue Ausdruckswertkategorien
- Semantik verschieben
Wenn wir die Konzepte der neuen Ausdruckswertkategorien verstehen möchten, müssen wir uns bewusst sein, dass es r- und l-Wert-Referenzen gibt. Es ist besser zu wissen, dass r-Werte an nicht konstante r-Wert-Referenzen übergeben werden können.
int& r_i=7; // compile error
int&& rr_i=7; // OK
Wir können uns ein Bild von den Konzepten der Wertekategorien machen, wenn wir den Unterabschnitt mit dem Titel Lvalues und rvalues aus dem Arbeitsentwurf N3337 (dem Entwurf, der dem veröffentlichten ISOC ++ 11-Standard am ähnlichsten ist) zitieren.
3.10 L-Werte und r-Werte [basic.lval]
1 Ausdrücke werden gemäß der Taxonomie in Abbildung 1 kategorisiert.
- Ein l-Wert (historisch so genannt, weil l-Werte auf der linken Seite eines Zuweisungsausdrucks erscheinen könnten) bezeichnet eine Funktion oder ein Objekt. [Beispiel: Wenn E ein Ausdruck vom Zeigertyp ist, dann ist * E ein l-Wert-Ausdruck, der sich auf das Objekt oder die Funktion bezieht, auf die E zeigt. Als weiteres Beispiel ist das Ergebnis des Aufrufs einer Funktion, deren Rückgabetyp eine lWertreferenz ist, ein lWert. - Beispiel beenden]
- Ein x-Wert (ein "eXpiring" -Wert) bezieht sich auch auf ein Objekt, normalerweise gegen Ende seiner Lebensdauer (damit beispielsweise seine Ressourcen verschoben werden können). Ein x-Wert ist das Ergebnis bestimmter Arten von Ausdrücken mit r-Wert-Referenzen (8.3.2). [Beispiel: Das Ergebnis des Aufrufs einer Funktion, deren Rückgabetyp eine rWertreferenz ist, ist ein xWert. - Beispiel beenden]
- Ein gl-Wert ("verallgemeinerter" l-Wert) ist ein l-Wert oder ein x-Wert.
- Ein r-Wert (historisch so genannt, weil r-Werte auf der rechten Seite eines Zuweisungsausdrucks erscheinen könnten) ist ein x-Wert, ein
temporäres Objekt (12.2) oder ein Unterobjekt davon oder ein Wert, der keinem
Objekt zugeordnet ist.
- Ein Wert ("reiner" Wert) ist ein Wert, der kein x-Wert ist. [Beispiel: Das Ergebnis des Aufrufs einer Funktion, deren Rückgabetyp keine
Referenz ist, ist ein Wert. Der Wert eines Literals wie 12, 7.3e5 oder
true ist ebenfalls ein Wert. - Beispiel beenden]
Jeder Ausdruck gehört genau zu einer der grundlegenden Klassifikationen in dieser Taxonomie: lvalue, xvalue oder prvalue. Diese Eigenschaft eines Ausdrucks wird als Wertkategorie bezeichnet.
Ich bin mir jedoch nicht ganz sicher, ob dieser Unterabschnitt ausreicht, um die Konzepte klar zu verstehen, da "normalerweise" nicht wirklich allgemein ist, "gegen Ende seiner Lebensdauer" nicht wirklich konkret ist, "Einbeziehung von Wertreferenzen" nicht wirklich klar ist. und "Beispiel: Das Ergebnis des Aufrufs einer Funktion, deren Rückgabetyp eine rWertreferenz ist, ist ein xWert." klingt wie eine Schlange ihren Schwanz beißt.
PRIMÄRWERTKATEGORIEN
Jeder Ausdruck gehört genau einer Primärwertkategorie an. Diese Wertekategorien sind die Kategorien lvalue, xvalue und prvalue.
lWerte
Der Ausdruck E gehört genau dann zur Kategorie lvalue, wenn sich E auf eine Entität bezieht, die BEREITS eine Identität (Adresse, Name oder Alias) hat, die sie außerhalb von E zugänglich macht.
#include <iostream>
int i=7;
const int& f(){
return i;
}
int main()
{
std::cout<<&"www"<<std::endl; // The expression "www" in this row is an lvalue expression, because string literals are arrays and every array has an address.
i; // The expression i in this row is an lvalue expression, because it refers to the same entity ...
i; // ... as the entity the expression i in this row refers to.
int* p_i=new int(7);
*p_i; // The expression *p_i in this row is an lvalue expression, because it refers to the same entity ...
*p_i; // ... as the entity the expression *p_i in this row refers to.
const int& r_I=7;
r_I; // The expression r_I in this row is an lvalue expression, because it refers to the same entity ...
r_I; // ... as the entity the expression r_I in this row refers to.
f(); // The expression f() in this row is an lvalue expression, because it refers to the same entity ...
i; // ... as the entity the expression f() in this row refers to.
return 0;
}
xWerte
Der Ausdruck E gehört genau dann zur Kategorie xvalue, wenn dies der Fall ist
- das Ergebnis des impliziten oder expliziten Aufrufs einer Funktion, deren Rückgabetyp eine rWert-Referenz auf den Typ des zurückgegebenen Objekts ist, oder
int&& f(){
return 3;
}
int main()
{
f(); // The expression f() belongs to the xvalue category, because f() return type is an rvalue reference to object type.
return 0;
}
- eine Umwandlung in einen r-Wert-Verweis auf den Objekttyp oder
int main()
{
static_cast<int&&>(7); // The expression static_cast<int&&>(7) belongs to the xvalue category, because it is a cast to an rvalue reference to object type.
std::move(7); // std::move(7) is equivalent to static_cast<int&&>(7).
return 0;
}
- ein Zugriffsausdruck für Klassenmitglieder, der ein nicht statisches Datenelement vom Nichtreferenztyp angibt, in dem der Objektausdruck ein x-Wert ist, oder
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;
}
- Ein Zeiger-zu-Element-Ausdruck, bei dem der erste Operand ein x-Wert und der zweite Operand ein Zeiger auf ein Datenelement ist.
Beachten Sie, dass die obigen Regeln bewirken, dass benannte rWert-Verweise auf Objekte als l-Werte und unbenannte rWert-Verweise auf Objekte als x-Werte behandelt werden. rWertreferenzen auf Funktionen werden als lWerte behandelt, unabhängig davon, ob sie benannt sind oder nicht.
#include <functional>
struct As
{
int i;
};
As&& f(){
return As();
}
int main()
{
f(); // The expression f() belongs to the xvalue category, because it refers to an unnamed rvalue reference to object.
As&& rr_a=As();
rr_a; // The expression rr_a belongs to the lvalue category, because it refers to a named rvalue reference to object.
std::ref(f); // The expression std::ref(f) belongs to the lvalue category, because it refers to an rvalue reference to function.
return 0;
}
Werte
Der Ausdruck E gehört genau dann zur Kategorie prvalue, wenn E weder zur Kategorie lvalue noch zur Kategorie xvalue gehört.
struct As
{
void f(){
this; // The expression this is a prvalue expression. Note, that the expression this is not a variable.
}
};
As f(){
return As();
}
int main()
{
f(); // The expression f() belongs to the prvalue category, because it belongs neither to the lvalue nor to the xvalue category.
return 0;
}
MIXED VALUE CATEGORIES
Es gibt zwei weitere wichtige Mischwertkategorien. Diese Wertekategorien sind rWert- und glWert-Kategorien.
rWerte
Der Ausdruck E gehört genau dann zur Kategorie rWert, wenn E zur Kategorie xWert oder zur Kategorie prWert gehört.
Beachten Sie, dass diese Definition bedeutet, dass der Ausdruck E genau dann zur r-Wert-Kategorie gehört, wenn sich E auf eine Entität bezieht, die keine Identität hat, die sie außerhalb von E YET zugänglich macht.
glWerte
Der Ausdruck E gehört genau dann zur Kategorie glvalue, wenn E zur Kategorie lvalue oder zur Kategorie xvalue gehört.
Eine praktische Regel
Scott Meyer hat veröffentlicht eine sehr nützliche Daumenregel rvalues von lvalues zu unterscheiden.
- Wenn Sie die Adresse eines Ausdrucks übernehmen können, ist der Ausdruck ein Wert.
- Wenn der Typ eines Ausdrucks eine l-Wert-Referenz ist (z. B. T & oder const T & usw.), ist dieser Ausdruck ein l-Wert.
- Andernfalls ist der Ausdruck ein r-Wert. Konzeptionell (und typischerweise auch tatsächlich) entsprechen r-Werte temporären Objekten, z. B. solchen, die von Funktionen zurückgegeben oder durch implizite Typkonvertierungen erstellt wurden. Die meisten Literalwerte (z. B. 10 und 5.3) sind ebenfalls r-Werte.