INTRODUCTION
ISOC ++ 11 (officiellement ISO / IEC 14882: 2011) est la version la plus récente de la norme du langage de programmation C ++. Il contient de nouvelles fonctionnalités et concepts, par exemple:
- références rvalue
- Catégories de valeurs d'expression xvalue, glvalue, prvalue
- déplacer la sémantique
Si nous voulons comprendre les concepts des nouvelles catégories de valeurs d'expression, nous devons être conscients qu'il existe des références rvalue et lvalue. Il est préférable de savoir que les valeurs r peuvent être transmises à des références rvalue non const.
int& r_i=7; // compile error
int&& rr_i=7; // OK
Nous pouvons acquérir une certaine intuition des concepts de catégories de valeurs si nous citons la sous-section intitulée Lvalues et rvalues du projet de travail N3337 (le projet le plus similaire à la norme ISOC ++ 11 publiée).
3.10 Lvalues et rvalues [basic.lval]
1 Les expressions sont classées selon la taxonomie de la figure 1.
- Une lvalue (ainsi appelée, historiquement, car des lvalues peuvent apparaître sur le côté gauche d'une expression d'affectation) désigne une fonction ou un objet. [Exemple: si E est une expression de type pointeur, alors * E est une expression de valeur se référant à l'objet ou à la fonction vers laquelle E pointe. Comme autre exemple, le résultat de l'appel d'une fonction dont le type de retour est une référence lvalue est une lvalue. —Fin exemple]
- Une valeur x (une valeur «eXpiring») fait également référence à un objet, généralement vers la fin de sa durée de vie (afin que ses ressources puissent être déplacées, par exemple). Une valeur x est le résultat de certains types d'expressions impliquant des références rvalue (8.3.2). [Exemple: Le résultat de l'appel d'une fonction dont le type de retour est une référence rvalue est une xvalue. —Fin exemple]
- Une glvalue (lvalue «généralisée») est une lvalue ou une xvalue.
- Une rvalue (ainsi appelée, historiquement, car les rvalues pouvaient apparaître sur le côté droit d'une expression d'affectation) est une valeur x, un
objet temporaire (12.2) ou un sous-objet de celui-ci, ou une valeur qui n'est pas
associée à un objet.
- Une valeur pr (valeur «pure») est une valeur r qui n'est pas une valeur x. [Exemple: Le résultat de l'appel d'une fonction dont le type de retour n'est pas une
référence est une valeur. La valeur d'un littéral tel que 12, 7.3e5 ou
true est également une valeur. —Fin exemple]
Chaque expression appartient exactement à l'une des classifications fondamentales de cette taxonomie: lvalue, xvalue ou prvalue. Cette propriété d'une expression est appelée sa catégorie de valeur.
Mais je ne suis pas sûr que cette sous-section soit suffisante pour comprendre clairement les concepts, car "généralement" n'est pas vraiment général, "vers la fin de sa durée de vie" n'est pas vraiment concret, "impliquant des références de valeur" n'est pas vraiment clair, et "Exemple: Le résultat de l'appel d'une fonction dont le type de retour est une référence rvalue est une valeur x." sonne comme un serpent se mord la queue.
CATÉGORIES DE VALEUR PRIMAIRE
Chaque expression appartient à exactement une catégorie de valeur principale. Ces catégories de valeurs sont les catégories lvalue, xvalue et prvalue.
lvaleurs
L'expression E appartient à la catégorie lvalue si et seulement si E fait référence à une entité qui a DÉJÀ une identité (adresse, nom ou alias) qui la rend accessible en dehors de E.
#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;
}
xvalues
L'expression E appartient à la catégorie xvalue si et seulement si elle est
- le résultat de l'appel d'une fonction, implicite ou explicite, dont le type de retour est une référence rvalue au type d'objet retourné, ou
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;
}
- un transtypage en une référence rvalue au type d'objet, ou
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;
}
- une expression d'accès de membre de classe désignant un membre de données non statique de type non référence dans lequel l'expression d'objet est une valeur x, ou
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;
}
- une expression pointeur sur membre dans laquelle le premier opérande est une valeur x et le second opérande est un pointeur sur un membre de données.
Notez que l'effet des règles ci-dessus est que les références rvalue nommées aux objets sont traitées comme des lvalues et les références rvalue sans nom aux objets sont traitées comme des xvalues; Les références rvalue aux fonctions sont traitées comme des lvalues, qu'elles soient nommées ou non.
#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;
}
valeurs
L'expression E appartient à la catégorie prvalue si et seulement si E n'appartient ni à la lvalue ni à la catégorie xvalue.
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;
}
CATÉGORIES À VALEUR MIXTE
Il existe deux autres catégories de valeurs mixtes importantes. Ces catégories de valeurs sont les catégories rvalue et glvalue.
rvalues
L'expression E appartient à la catégorie rvalue si et seulement si E appartient à la catégorie xvalue ou à la catégorie prvalue.
Notez que cette définition signifie que l'expression E appartient à la catégorie rvalue si et seulement si E fait référence à une entité qui n'a pas eu d'identité qui la rend accessible en dehors de E YET.
glvalues
L'expression E appartient à la catégorie glvalue si et seulement si E appartient à la catégorie lvalue ou à la catégorie xvalue.
UNE RÈGLE PRATIQUE
Scott Meyer a publié une règle empirique très utile pour distinguer les valeurs r des valeurs l.
- Si vous pouvez prendre l'adresse d'une expression, l'expression est une valeur l.
- Si le type d'une expression est une référence lvalue (par exemple, T & ou const T &, etc.), cette expression est une lvalue.
- Sinon, l'expression est une valeur r. Conceptuellement (et généralement aussi en fait), les valeurs r correspondent à des objets temporaires, tels que ceux renvoyés par des fonctions ou créés par des conversions de types implicites. La plupart des valeurs littérales (par exemple, 10 et 5.3) sont également des valeurs r.