INTRODUZIONE
ISOC ++ 11 (ufficialmente ISO / IEC 14882: 2011) è la versione più recente dello standard del linguaggio di programmazione C ++. Contiene alcune nuove funzionalità e concetti, ad esempio:
- riferimenti di valore
- categorie di valori dell'espressione xvalue, glvalue, prvalue
- spostare la semantica
Se desideriamo comprendere i concetti delle nuove categorie di valori delle espressioni, dobbiamo essere consapevoli del fatto che esistono riferimenti rvalue e lvalue. È meglio sapere che i valori possono essere passati a riferimenti a valori non costanti.
int& r_i=7; // compile error
int&& rr_i=7; // OK
Possiamo ottenere alcune intuizioni dei concetti di categorie di valori se citiamo la sottosezione intitolata Valori e valori dal progetto di lavoro N3337 (il progetto più simile allo standard ISOC ++ 11 pubblicato).
3.10 Valori e valori [basic.lval]
1 Le espressioni sono classificate in base alla tassonomia nella Figura 1.
- Un lvalue (così chiamato, storicamente, perché i lvalues potrebbero apparire sul lato sinistro di un'espressione di assegnazione) designa una funzione o un oggetto. [Esempio: se E è un'espressione di tipo puntatore, allora * E è un'espressione lvalore che si riferisce all'oggetto o alla funzione a cui E punta. Come altro esempio, il risultato della chiamata di una funzione il cui tipo restituito è un riferimento lvalue è un lvalue. —End esempio]
- Un valore x (un valore "eXpiring") si riferisce anche a un oggetto, di solito vicino alla fine della sua vita (in modo che le sue risorse possano essere spostate, ad esempio). Un xvalue è il risultato di alcuni tipi di espressioni che coinvolgono riferimenti rvalue (8.3.2). [Esempio: il risultato della chiamata di una funzione il cui tipo restituito è un riferimento di valore è un valore x. —End esempio]
- Un valore (valore “generalizzato”) è un valore o un valore x.
- Un valore (così chiamato, storicamente, perché i valori possono apparire sul lato destro di un'espressione di assegnazione) è un valore x, un
oggetto temporaneo (12.2) o un oggetto secondario o un valore che non è
associato a un oggetto.
- Un valore (valore "puro") è un valore che non è un valore x. [Esempio: il risultato della chiamata di una funzione il cui tipo restituito non è un
riferimento è un valore. Anche il valore di un valore letterale come 12, 7.3e5 o
true è un valore. —Esempio]
Ogni espressione appartiene esattamente a una delle classificazioni fondamentali in questa tassonomia: lvalue, xvalue o prvalue. Questa proprietà di un'espressione è chiamata la sua categoria di valore.
Ma non sono del tutto sicuro che questa sottosezione sia sufficiente per comprendere chiaramente i concetti, perché "di solito" non è veramente generale, "verso la fine della sua vita" non è molto concreto, "coinvolgere riferimenti di valore" non è molto chiaro, e "Esempio: il risultato della chiamata di una funzione il cui tipo restituito è un riferimento di valore è un valore x". sembra che un serpente si morda la coda.
CATEGORIE DI VALORI PRIMARI
Ogni espressione appartiene esattamente a una categoria di valore primario. Queste categorie di valori sono categorie lvalue, xvalue e prvalue.
lvalue
L'espressione E appartiene alla categoria lvalue se e solo se E si riferisce a un'entità che GIÀ ha avuto un'identità (indirizzo, nome o alias) che la rende accessibile al di fuori di 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'espressione E appartiene alla categoria xvalue se e solo se lo è
- il risultato della chiamata di una funzione, implicitamente o esplicitamente, il cui tipo restituito è un riferimento di valore al tipo di oggetto restituito, oppure
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 cast in riferimento a un valore rvalore al tipo di oggetto, oppure
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;
}
- un'espressione di accesso di un membro della classe che designa un membro di dati non statico di tipo non di riferimento in cui l'espressione dell'oggetto è un valore x, oppure
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;
}
- un'espressione da puntatore a membro in cui il primo operando è un valore x e il secondo operando è un puntatore al membro dati.
Si noti che l'effetto delle regole precedenti è che i riferimenti ai valori nominali agli oggetti sono trattati come valori e i riferimenti ai valori senza nome agli oggetti sono trattati come valori x; i riferimenti rvalue alle funzioni sono trattati come lvalues con o senza nome.
#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;
}
prvalues
L'espressione E appartiene alla categoria prvalue se e solo se E non appartiene né alla categoria lvalue né alla categoria 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;
}
CATEGORIE DI VALORI MISTI
Esistono altre due importanti categorie di valori misti. Queste categorie di valori sono categorie rvalue e glvalue.
rvalues
L'espressione E appartiene alla categoria rvalue se e solo se E appartiene alla categoria xvalue o alla categoria prvalue.
Si noti che questa definizione significa che l'espressione E appartiene alla categoria del valore se e solo se E si riferisce a un'entità che non ha avuto alcuna identità che lo rende accessibile al di fuori di E YET.
glvalues
L'espressione E appartiene alla categoria glvalue se e solo se E appartiene alla categoria lvalue o alla categoria xvalue.
UNA REGOLA PRATICA
Scott Meyer ha pubblicato una regola empirica molto utile per distinguere i valori dai valori.
- Se riesci a prendere l'indirizzo di un'espressione, l'espressione è un valore.
- Se il tipo di un'espressione è un riferimento lvalue (ad esempio, T & o const T &, ecc.), Quell'espressione è un lvalue.
- Altrimenti, l'espressione è un valore. Concettualmente (e in genere anche nei fatti), i valori corrispondono ad oggetti temporanei, come quelli restituiti da funzioni o creati attraverso conversioni di tipo implicite. La maggior parte dei valori letterali (ad es. 10 e 5.3) sono anche valori.