Nota: Un valore o un letterale è ancora un'espressione, quindi questi termini classificano le espressioni e non veramente valori.
glvalue e rvalue sono i due sottoinsiemi dall'espressione del big set. GlValue esiste in altri due sottoinsiemi: lValue e XValue. RValue, l'altro sottoinsieme per l'espressione, esiste anche in altri due sottoinsiemi: XValue e Prvalue. Quindi, XValue è un sottoinsieme di glvalue e rValue: cioè XValue è l'intersezione di Glvalue e RValue. Il seguente diagramma di tassonomia, tratto dalla specifica C ++, illustra la relazione di tutti i set:
Prvalue, XValue e LValue sono i valori della categoria primaria. Glvalue è l'unione di lvalues e xvalori, mentre i rvalori sono l'unione di xvalori e prvalori.
Hai bisogno di conoscenze di base in C ++ per comprendere questo articolo; Hai anche bisogno di conoscenza della portata in C++.
Contenuto dell'articolo
Nozioni di base
Per comprendere veramente la tassonomia della categoria di espressione, è necessario ricordare o conoscere prima le seguenti caratteristiche di base: posizione e oggetto, archiviazione e risorsa, inizializzazione, identificatore e riferimento, riferimenti LVALUE e RVALUE, puntatore, punta gratuita e riutilizzo di a risorsa.
Posizione e oggetto
Considera la seguente dichiarazione:
int ident;
Questa è una dichiarazione che identifica una posizione in memoria. Una posizione è una serie particolare di byte consecutivi in memoria. Una posizione può consistere in un byte, due byte, quattro byte, sessantaquattro byte, ecc. La posizione per un numero intero per una macchina a 32 bit è di quattro byte. Inoltre, la posizione può essere identificata da un identificatore.
Nella dichiarazione di cui sopra, la posizione non ha alcun contenuto. Significa che non ha alcun valore, poiché il contenuto è il valore. Quindi, un identificatore identifica una posizione (piccolo spazio continuo). Quando la posizione viene assegnato un contenuto particolare, l'identificatore identifica sia la posizione che il contenuto; Cioè, l'identificatore identifica quindi sia la posizione che il valore.
Considera le seguenti affermazioni:
int ident1 = 5;
int ident2 = 100;
Ognuna di queste affermazioni è una dichiarazione e una definizione. Il primo identificatore ha il valore (contenuto) 5 e il secondo identificatore ha il valore 100. In una macchina a 32 bit, ciascuna di queste posizioni è lunga quattro byte. Il primo identificatore identifica sia una posizione che un valore. Il secondo identificatore identifica anche entrambi.
Un oggetto è una regione di archiviazione nominata in memoria. Quindi, un oggetto è una posizione senza un valore o una posizione con un valore.
Archiviazione e risorsa degli oggetti
La posizione per un oggetto è anche chiamata archiviazione o risorsa dell'oggetto.
Inizializzazione
Considera il seguente segmento di codice:
int ident;
IDIT = 8;
La prima riga dichiara un identificatore. Questa dichiarazione fornisce una posizione (archiviazione o risorsa) per un oggetto intero, identificandolo con il nome, identificativo. La riga successiva mette il valore 8 (in bit) nella posizione identificata per identifica. Il punto di questo valore è l'inizializzazione.
La seguente istruzione definisce un vettore con contenuto, 1, 2, 3, 4, 5, identificato da VTR:
std :: vector vtr 1, 2, 3, 4, 5;
Qui, l'inizializzazione con 1, 2, 3, 4, 5 viene eseguita nella stessa affermazione della definizione (Dichiarazione). L'operatore di assegnazione non viene utilizzato. La seguente istruzione definisce un array con il contenuto 1, 2, 3, 4, 5:
int arr [] = 1, 2, 3, 4, 5;
Questa volta, un operatore di assegnazione è stato utilizzato per l'inizializzazione.
Identificatore e riferimento
Considera il seguente segmento di codice:
int ident = 4;
int & ref1 = Identi;
int & ref2 = IDent;
cout<< ident <<"<< ref1 <<"<< ref2 << '\n';
L'output è:
4 4 4Identi è un identificatore, mentre Ref1 e Ref2 sono riferimenti; fanno riferimento alla stessa posizione. Un riferimento è sinonimo di un identificatore. Convenzionalmente, Ref1 e Ref2 sono nomi diversi di un oggetto, mentre l'identificazione è l'identificatore dello stesso oggetto. Tuttavia, l'identità può ancora essere chiamato il nome dell'oggetto, il che significa, identificarsi, ref1 e ref2 la stessa posizione.
La differenza principale tra un identificatore e un riferimento è che, quando passata come argomento a una funzione, se passata dall'identificatore, viene effettuata una copia per l'identificatore nella funzione, mentre se passata per riferimento, la stessa posizione viene utilizzata all'interno del funzione. Quindi, il passaggio per identificatore finisce con due posizioni, mentre il passaggio per riferimento finisce con la stessa posizione.
Riferimento di LValue e riferimento per la rValue
Il modo normale per creare un riferimento è il seguente:
int ident;
IDIT = 4;
int & ref = Identi;
L'archiviazione (risorsa) viene localizzato e identificato per primo (con un nome come Identi. Quando si passa come argomento a una funzione, una copia dell'identificatore verrà effettuata nella funzione, mentre per il caso di un riferimento, verrà utilizzata la posizione originale (citata) nella funzione.
Oggi è possibile avere solo un riferimento senza identificarlo. Ciò significa che è possibile creare prima un riferimento senza avere un identificatore per la posizione. Questo usa &&, come mostrato nella seguente affermazione:
int && ref = 4;
Qui, non c'è identificazione precedente. Per accedere al valore dell'oggetto, usa semplicemente il Ref come utilizzeresti l'identità sopra.
Con la dichiarazione &&, non vi è alcuna possibilità di trasmettere un argomento a una funzione da parte dell'identificatore. L'unica scelta è passare per riferimento. In questo caso, c'è solo una posizione utilizzata all'interno della funzione e non la seconda posizione copiata come con un identificatore.
Una dichiarazione di riferimento con & si chiama riferimento LValue. Una dichiarazione di riferimento con && si chiama riferimento RValue, che è anche un riferimento a prValue (vedi sotto).
Pointer
Considera il seguente codice:
int ptdint = 5;
int *ptrint;
ptrint = &ptdInt;
cout<< *ptrInt <<'\n';
L'output è 5.
Qui, ptdint è un identificatore come l'identità sopra. Ci sono due oggetti (posizioni) qui invece di uno: l'oggetto appuntito, ptdint identificato da ptdint e l'oggetto puntatore, ptrint identificato da ptrint. & ptdint restituisce l'indirizzo dell'oggetto appuntito e lo mette come valore nell'oggetto PTRINT puntatore. Per restituire (ottenere) il valore dell'oggetto appuntito, utilizzare l'identificatore per l'oggetto puntatore, come in "*ptrint".
Nota: ptdint è un identificatore e non un riferimento, mentre il nome, ref, menzionato in precedenza, è un riferimento.
La seconda e la terza riga nel codice sopra possono essere ridotte a una riga, portando al seguente codice:
int ptdint = 5;
int *ptrint = &ptdInt;
cout<< *ptrInt <<'\n';
Nota: Quando un puntatore viene incrementato, punta alla posizione successiva, che non è un'aggiunta del valore 1. Quando un puntatore viene decrementato, indica la posizione precedente, che non è una sottrazione del valore 1.
Negozio gratuito
Un sistema operativo alloca la memoria per ciascun programma in esecuzione. Una memoria che non è assegnata a nessun programma è noto come negozio gratuito. L'espressione che restituisce una posizione per un numero intero dal negozio gratuito è:
Nuovo int
Ciò restituisce una posizione per un numero intero che non è identificato. Il seguente codice illustra come utilizzare il puntatore con il negozio gratuito:
int *ptrint = new int;
*ptrint = 12;
cout<< *ptrInt <<'\n';
L'output è 12.
Per distruggere l'oggetto, utilizzare l'espressione di eliminazione come segue:
Elimina ptrint;
L'argomento all'espressione di Elimina è un puntatore. Il seguente codice illustra il suo uso:
int *ptrint = new int;
*ptrint = 12;
Elimina ptrint;
cout<< *ptrInt <<'\n';
L'output è 0, e non niente come null o indefinito. Elimina sostituisce il valore per la posizione con il valore predefinito del tipo particolare della posizione, quindi consente la posizione per il riutilizzo. Il valore predefinito per una posizione int è 0.
Riutilizzare una risorsa
Nella tassonomia della categoria di espressione, il riutilizzo di una risorsa è lo stesso che riutilizzare una posizione o archiviazione per un oggetto. Il seguente codice illustra come riutilizzare una posizione da Free Store:
int *ptrint = new int;
*ptrint = 12;
cout<< *ptrInt <<'\n';
Elimina ptrint;
cout<< *ptrInt <<'\n';
*ptrint = 24;
cout<< *ptrInt <<'\n';
L'output è:
12Un valore di 12 viene assegnato per la prima volta alla posizione non identificata. Quindi il contenuto della posizione viene eliminato (in teoria l'oggetto viene eliminato). Il valore di 24 è riassegnato nella stessa posizione.
Il seguente programma mostra come viene riutilizzato un riferimento intero restituito da una funzione:
#includere
Utilizzo dello spazio dei nomi std;
int & fn ()
int i = 5;
int & j = i;
ritorno j;
int main ()
int & myint = fn ();
cout<< myInt <<'\n';
myint = 17;
cout<< myInt <<'\n';
restituzione 0;
L'output è:
5Un oggetto come I, dichiarato nell'ambito locale (portata della funzione), cessa di esistere alla fine dell'ambito locale. Tuttavia, la funzione fn () sopra, restituisce il riferimento di i. Attraverso questo riferimento restituito, il nome, myint nella funzione principale (), riutilizza la posizione identificata da I per il valore 17.
lValue
Un LVALUE è un'espressione la cui valutazione determina l'identità di un oggetto, un campo di bit o una funzione. L'identità è un'identità ufficiale come l'identità sopra, o un nome di riferimento LValue, un puntatore o il nome di una funzione. Considera il seguente codice che funziona:
int myint = 512;
int & myref = myint;
int* ptr = &myInt;
int fn ()
++PTR; --ptr;
restituire myint;
Qui, Myint è un LVALUE; Myref è un'espressione di riferimento LValue; *PTR è un'espressione LVALUE perché il suo risultato è identificabile con PTR; ++ PTR o -PTR è un'espressione LValue perché il suo risultato è identificabile con il nuovo stato (indirizzo) di PTR e FN è un LVALUE (espressione).
Considera il seguente segmento di codice:
int a = 2, b = 8;
int c = a + 16 + b + 64;
Nella seconda affermazione, la posizione per "A" ha 2 ed è identificabile da "A", e così è un lValue. La posizione per B ha 8 ed è identificabile da B, e così è un LVALUE. La posizione per C avrà la somma ed è identificabile da C, e così è un LVALUE. Nella seconda affermazione, le espressioni o i valori di 16 e 64 sono rvalori (vedi sotto).
Considera il seguente segmento di codice:
char seq [5];
seq [0] = 'l', seq [1] = 'o', seq [2] = 'v', seq [3] = 'e', seq [4] = '\ 0';
cout<< seq[2] <<'\n';
L'output è 'v';
Seq è un array. La posizione per "V" o qualsiasi valore simile nell'array è identificata da seq [i], dove i è un indice. Quindi, l'espressione, seq [i], è un'espressione di lValue. Seq, che è l'identificatore per l'intero array, è anche un lValue.
prvalue
Un prvalue è un'espressione la cui valutazione inizializza un oggetto o un campo bit o calcola il valore dell'operando di un operatore, come specificato dal contesto in cui appare.
Nella dichiarazione,
int myint = 256;
256 è un prvalue (espressione prvalue) che inizializza l'oggetto identificato da myint. Questo oggetto non è referenziato.
Nella dichiarazione,
int && ref = 4;
4 è un prvalue (espressione prvalue) che inizializza l'oggetto a cui si fa riferimento. Questo oggetto non viene identificato ufficialmente. Il REF è un esempio di espressione di riferimento di RValue o di espressione di riferimento di prValue; È un nome, ma non un identificatore ufficiale.
Considera il seguente segmento di codice:
int ident;
IDIT = 6;
int & ref = Identi;
6 è un prvalue che inizializza l'oggetto identificato per identità; L'oggetto è anche referenziato da Ref. Qui, l'arbitro è un riferimento a lValue e non un riferimento.
Considera il seguente segmento di codice:
int a = 2, b = 8;
int c = a + 15 + b + 63;
15 e 63 sono ciascuno una costante che si calcola a se stessa, producendo un operando (in bit) per l'operatore di addizione. Quindi, 15 o 63 è un'espressione prValue.
Qualsiasi letterale, tranne la corda letterale, è un prvalue (i.e., un'espressione prvalue). Quindi, un letterale come 58 o 58.53, o vero o falso, è un prvalue. Un letterale può essere usato per inizializzare un oggetto o calcola a se stesso (in qualche altra forma in bit) come valore di un operando per un operatore. Nel codice sopra, il letterale 2 inizializza l'oggetto, a. Si calcola anche come operando per l'operatore di assegnazione.
Perché una stringa letterale non è un prvalue? Considera il seguente codice:
char str [] = "amore non odio";
cout << str <<'\n';
cout << str[5] <<'\n';
L'output è:
Non amare l'odioSTR identifica l'intera stringa. Quindi, l'espressione, STR e non ciò che identifica, è un LVALUE. Ogni carattere nella stringa può essere identificato da str [i], dove i è un indice. L'espressione, STR [5], e non il personaggio che identifica, è un lValue. La stringa letterale è un lvalue e non un prvalue.
Nella seguente dichiarazione, un array letterale inizializza l'oggetto, arr:
ptrint ++ o ptrint--
Qui, Ptrint è un puntatore a una posizione intera. L'intera espressione, e non il valore finale della posizione in cui punta, è un prvalue (espressione). Questo perché l'espressione, ptrint ++ o ptrint-, identifica il primo valore originale della sua posizione e non il secondo valore finale della stessa posizione. Dall'altra parte, -Ptrint o -Ptrint è un LVALUE perché identifica l'unico valore dell'interesse nella posizione. Un altro modo di guardarlo è che il valore originale calcola il secondo valore finale.
Nella seconda dichiarazione del seguente codice, A o B può ancora essere considerato come un prvalue:
int a = 2, b = 8;
int c = a + 15 + b + 63;
Quindi, A o B nella seconda affermazione è un LVALUE perché identifica un oggetto. È anche un prvalue poiché calcola l'intero di un operatore per l'operatore di addizione.
(nuovo int), e non la posizione che stabilisce è un prvalue. Nella seguente dichiarazione, l'indirizzo di ritorno della posizione è assegnato a un oggetto puntatore:
int *ptrint = new int
Qui, *ptrint è un lValue, mentre (nuovo int) è un prvalue. Ricorda, un LVALUE o un Prvalue è un'espressione. (nuovo int) non identifica alcun oggetto. Restituzione dell'indirizzo non significa identificare l'oggetto con un nome (come Identi, sopra). In *ptrint, il nome, ptrint, è ciò che identifica davvero l'oggetto, quindi *ptrint è un lValue. D'altra parte, (nuovo int) è un prvalue, in quanto calcola una nuova posizione a un indirizzo del valore operativo per l'operatore di assegnazione =.
XValue
Oggi, LValue sta per il valore della posizione; PRVALUE sta per RValue "puro" (vedi cosa rappresenta RValue per). Oggi XValue sta per "scadere" LVALUE.
La definizione di XValue, citata dalla specifica C ++, è la seguente:
“Un XValue è un GlValue che indica un oggetto o un campo bit le cui risorse possono essere riutilizzate (di solito perché è vicino alla fine della sua vita). [Esempio: alcuni tipi di espressioni che coinvolgono riferimenti RValue producono XValues, come una chiamata a una funzione il cui tipo di ritorno è un riferimento RValue o un cast a un esempio di tipo di riferimento di riferimento RValue] "
Ciò significa che possono scadere sia LValue che. Il seguente codice (copiato dall'alto) mostra come l'archiviazione (risorsa) di lValue, *ptrint viene riutilizzata dopo che è stata eliminata.
int *ptrint = new int;
*ptrint = 12;
cout<< *ptrInt <<'\n';
Elimina ptrint;
cout<< *ptrInt <<'\n';
*ptrint = 24;
cout<< *ptrInt <<'\n';
L'output è:
12Il seguente programma (copiato dall'alto) mostra come l'archiviazione di un riferimento intero, che è un riferimento LValue restituito da una funzione, viene riutilizzato nella funzione principale ():
#includere
Utilizzo dello spazio dei nomi std;
int & fn ()
int i = 5;
int & j = i;
ritorno j;
int main ()
int & myint = fn ();
cout<< myInt <<'\n';
myint = 17;
cout<< myInt <<'\n';
restituzione 0;
L'output è:
5Quando un oggetto come I nella funzione fn () esce dall'ambito, viene naturalmente distrutto. In questo caso, la memoria di I è stata ancora riutilizzata nella funzione principale ().
I due campioni di codice sopra illustrano il riutilizzo della memoria di LValues. È possibile avere un riutilizzo di archiviazione di prvalues (rvalori) (vedi più avanti).
La seguente citazione relativa a XValue è dalla specifica C ++:
“In generale, l'effetto di questa regola è che i riferimenti nominati RValue sono trattati come LValues e i riferimenti di RValue senza nome agli oggetti sono trattati come XValues. I riferimenti di RValue alle funzioni sono trattati come LVALUE."(Vedi più tardi).
Quindi, un XValue è un LVALUE o un prvalue le cui risorse (archiviazione) possono essere riutilizzate. XValues è l'insieme di intersezione di LVALUE E PRVALUES.
C'è di più in XValue rispetto a quello che è stato affrontato in questo articolo. Tuttavia, XValue merita un intero articolo da solo, e quindi le specifiche extra per XValue non sono affrontate in questo articolo.
Set di tassonomio della categoria di espressione
Un'altra citazione dalla specifica C ++:
"Nota: Storicamente, LValues e RValues erano cosiddetti perché potevano apparire sul lato sinistro e destro di un incarico (sebbene questo non sia più generalmente vero); i glvalues sono lValues "generalizzati", i prvalori sono rvalori "puri" e XValues stanno "scadute" LVALUE. Nonostante i loro nomi, questi termini classificano le espressioni, non i valori. - Nota finale "
Quindi, GlValues è l'insieme sindacale di LValues, XValues e RValues sono l'insieme sindacale di XValues e prvalues. XValues è l'insieme di intersezione di LVALUE E PRVALUES.
A partire da ora, la tassonomia della categoria di espressione è meglio illustrata con un diagramma di Venn come segue:
Conclusione
Un LVALUE è un'espressione la cui valutazione determina l'identità di un oggetto, un campo di bit o una funzione.
Un prvalue è un'espressione la cui valutazione inizializza un oggetto o un campo bit o calcola il valore dell'operando di un operatore, come specificato dal contesto in cui appare.
Un XValue è un lVal o un prvalue, con la proprietà aggiuntiva che le sue risorse (archiviazione) possono essere riutilizzate.
La specifica C ++ illustra la tassonomia della categoria di espressione con un diagramma ad albero, che indica che c'è una gerarchia nella tassonomia. A partire da ora, non c'è gerarchia nella tassonomia, quindi un diagramma di Venn viene utilizzato da alcuni autori, in quanto illustra la tassonomia meglio del diagramma degli alberi.