C ++

Ekspressionskategoritaksonomi i C ++

Ekspressionskategoritaksonomi i C ++

En beregning er enhver form for beregning, der følger en veldefineret algoritme. Et udtryk er en sekvens af operatorer og operander, der specificerer en beregning. Med andre ord er et udtryk en identifikator eller en bogstavelig, eller en sekvens af begge, forbundet med operatorer.Under programmering kan et udtryk resultere i en værdi og / eller få noget til at ske. Når det resulterer i en værdi, er udtrykket en glvalue, rvalue, lvalue, xvalue eller prvalue. Hver af disse kategorier er et sæt udtryk. Hvert sæt har en definition og bestemte situationer, hvor dets betydning hersker, idet den adskiller den fra et andet sæt. Hvert sæt kaldes en værdikategori.

Bemærk: En værdi eller bogstavelig er stadig et udtryk, så disse udtryk klassificerer udtryk og ikke rigtig værdier.

glvalue og rvalue er de to undergrupper fra det store sæt udtryk. glvalue findes i yderligere to undergrupper: lvalue og xvalue. rvalue, den anden delmængde til ekspression, findes også i yderligere to undergrupper: xvalue og prvalue. Så, xvalue er en delmængde af både glvalue og rvalue: det vil sige xvalue er skæringspunktet mellem både glvalue og rvalue. Følgende taksonomidiagram taget fra C ++ specifikationen illustrerer forholdet mellem alle sæt:

prvalue, xvalue og lvalue er de primære kategoriværdier. glvalue er foreningen af ​​værdier og x-værdier, mens r-værdier er foreningen af ​​x-værdier og værdier.

Du har brug for grundlæggende viden i C ++ for at forstå denne artikel; du har også brug for viden om omfang i C++.

Artikelindhold

Grundlæggende

For virkelig at forstå udtrykkets kategoritaksonomi skal du først huske eller kende følgende grundlæggende funktioner: placering og objekt, opbevaring og ressource, initialisering, identifikator og reference, lvalue og rvalue referencer, pointer, gratis butik og genbrug af en ressource.

Placering og objekt

Overvej følgende erklæring:

int ident;

Dette er en erklæring, der identificerer en placering i hukommelsen. En placering er et bestemt sæt på hinanden følgende bytes i hukommelsen. En placering kan bestå af en byte, to byte, fire byte, 64 byte osv. Placeringen af ​​et heltal for en 32-bit maskine er fire byte. Placeringen kan også identificeres ved hjælp af en identifikator.

I ovenstående erklæring har placeringen ikke noget indhold. Det betyder, at det ikke har nogen værdi, da indholdet er værdien. Så en identifikator identificerer en placering (lille kontinuerligt rum). Når placeringen får et bestemt indhold, identificerer identifikatoren så både placeringen og indholdet; det vil sige, at identifikatoren derefter identificerer både placeringen og værdien.

Overvej følgende udsagn:

int ident1 = 5;
int ident2 = 100;

Hver af disse udsagn er en erklæring og en definition. Den første identifikator har værdien (indhold) 5, og den anden identifikator har værdien 100. I en 32-bit maskine er hver af disse placeringer fire byte lange. Den første identifikator identificerer både en placering og en værdi. Den anden identifikator identificerer også begge.

Et objekt er et navngivet lagerområde i hukommelsen. Så et objekt er enten en placering uden en værdi eller en placering med en værdi.

Objektlagring og ressource

Placeringen af ​​et objekt kaldes også objektets lagring eller ressource.

Initialisering

Overvej følgende kodesegment:

int ident;
ident = 8;

Den første linje erklærer en identifikator. Denne erklæring giver en placering (opbevaring eller ressource) for et heltal-objekt, der identificerer det med navnet, ident. Den næste linje sætter værdien 8 (i bit) på det sted, der identificeres af ident. Anbringelsen af ​​denne værdi er initialisering.

Følgende udsagn definerer en vektor med indhold, 1, 2, 3, 4, 5, identificeret ved vtr:

std :: vektor vtr 1, 2, 3, 4, 5;

Her foretages initialiseringen med 1, 2, 3, 4, 5 i samme sætning som definitionen (erklæring). Tildelingsoperatøren bruges ikke. Følgende udsagn definerer en matrix med indhold 1, 2, 3, 4, 5:

int arr [] = 1, 2, 3, 4, 5;

Denne gang er en tildelingsoperatør blevet brugt til initialiseringen.

Identifikator og reference

Overvej følgende kodesegment:

int ident = 4;
int & ref1 = ident;
int & ref2 = ident;
cout<< ident <<"<< ref1 <<"<< ref2 << '\n';

Outputtet er:

4 4 4

ident er en identifikator, mens ref1 og ref2 er referencer; de refererer til den samme placering. En reference er et synonym med en identifikator. Konventionelt er ref1 og ref2 forskellige navne på et objekt, mens ident er identifikatoren for det samme objekt. Imidlertid kan ident stadig kaldes objektets navn, hvilket betyder, ident, ref1 og ref2 navngiver den samme placering.

Hovedforskellen mellem en identifikator og en reference er, at når den sendes som et argument til en funktion, hvis den sendes med en identifikator, laves en kopi til identifikatoren i funktionen, mens den samme placering bruges inden for fungere. Så forbipasserende identifikator ender med to placeringer, mens forbipasserende ender med det samme sted.

lvalue Reference og rvalue Reference

Den normale måde at oprette en reference på er som følger:

int ident;
ident = 4;
int & ref = ident;

Lagringen (ressource) lokaliseres og identificeres først (med et navn som ident), og derefter foretages en reference (med et navn såsom en ref). Når der overføres som et argument til en funktion, vil der blive lavet en kopi af identifikatoren i funktionen, mens den oprindelige placering i tilfælde af en reference bruges (henvist til) i funktionen.

I dag er det muligt bare at have en reference uden at identificere den. Det betyder, at det er muligt først at oprette en reference uden at have en identifikator for placeringen. Dette bruger &&, som vist i følgende udsagn:

int && ref = 4;

Her er der ingen forudgående identifikation. For at få adgang til objektets værdi skal du blot bruge ref, som du ville bruge identiteten ovenfor.

Med &&-erklæringen er der ingen mulighed for at videregive et argument til en funktion ved hjælp af identifikator. Det eneste valg er at passere ved reference. I dette tilfælde er der kun en placering brugt inden for funktionen og ikke den anden kopierede placering som med en identifikator.

En referenceerklæring med & kaldes lvalue reference. En referenceerklæring med && kaldes rvalue reference, som også er en prvalue reference (se nedenfor).

Markør

Overvej følgende kode:

int ptdInt = 5;
int * ptrInt;
ptrInt = &ptdInt;
cout<< *ptrInt <<'\n';

Outputtet er 5.

Her er ptdInt en identifikator som identen ovenfor. Der er to objekter (placeringer) her i stedet for et: det spidse objekt, ptdInt identificeret ved ptdInt, og markørobjektet, ptrInt identificeret ved ptrInt. & ptdInt returnerer adressen på det spidse objekt og sætter det som værdien i markøren ptrInt-objekt. For at returnere (opnå) værdien af ​​det spidse objekt skal du bruge identifikatoren til markørobjektet, som i “* ptrInt”.

Bemærk: ptdInt er en identifikator og ikke en reference, mens navnet, ref, tidligere nævnt, er en reference.

Den anden og tredje linje i ovenstående kode kan reduceres til en linje, hvilket fører til følgende kode:

int ptdInt = 5;
int * ptrInt = &ptdInt;
cout<< *ptrInt <<'\n';

Bemærk: Når en markør er inkrementeret, peger den på den næste placering, hvilket ikke er en tilføjelse af værdien 1. Når en markør mindskes, peger den på den forrige placering, som ikke er en subtraktion af værdien 1.

Gratis butik

Et operativsystem tildeler hukommelse til hvert program, der kører. En hukommelse, der ikke er tildelt noget program, kaldes den gratis butik. Udtrykket, der returnerer et sted for et heltal fra den gratis butik, er:

ny int

Dette returnerer en placering for et heltal, der ikke er identificeret. Følgende kode illustrerer, hvordan du bruger markøren med den gratis butik:

int * ptrInt = ny int;
* ptrInt = 12;
cout<< *ptrInt  <<'\n';

Outputtet er 12.

For at ødelægge objektet skal du bruge sletteudtrykket som følger:

slet ptrInt;

Argumentet for sletteudtrykket er en markør. Følgende kode illustrerer dens anvendelse:

int * ptrInt = ny int;
* ptrInt = 12;
slet ptrInt;
cout<< *ptrInt <<'\n';

Outputtet er 0, og ikke noget som null eller udefineret. delete erstatter værdien for placeringen med standardværdien for den bestemte placeringstype og tillader derefter placeringen til genbrug. Standardværdien for en int-placering er 0.

Genbrug af en ressource

I ekspressionskategoritaksonomi er genbrug af en ressource det samme som genbrug af en placering eller opbevaring af et objekt. Følgende kode illustrerer, hvordan en placering fra gratis butik kan genbruges:

int * ptrInt = ny int;
* ptrInt = 12;
cout<< *ptrInt <<'\n';
slet ptrInt;
cout<< *ptrInt <<'\n';
* ptrInt = 24;
cout<< *ptrInt <<'\n';

Outputtet er:

12
0
24

En værdi på 12 tildeles først den uidentificerede placering. Derefter slettes indholdet af placeringen (i teorien slettes objektet). Værdien af ​​24 tildeles den samme placering igen.

Følgende program viser, hvordan et heltalsreference, der returneres af en funktion, genbruges:

#omfatte
ved hjælp af namespace std;
int & fn ()

int i = 5;
int & j = i;
returnere j;

int main ()

int & myInt = fn ();
cout<< myInt <<'\n';
myInt = 17;
cout<< myInt <<'\n';
returnere 0;

Outputtet er:

5
17

Et objekt som i, erklæret i et lokalt omfang (funktionsomfang), ophører med at eksistere i slutningen af ​​det lokale omfang. Funktionen fn () ovenfor returnerer imidlertid referencen for i. Gennem denne returnerede reference genbruger navnet, myInt i hovedfunktionen () den placering, der er identificeret af i for værdien 17.

værdi

En lvalue er et udtryk, hvis evaluering bestemmer identiteten af ​​et objekt, bitfelt eller funktion. Identiteten er en officiel identitet som ident ovenfor eller et referencenavn på en værdi, en markør eller navnet på en funktion. Overvej følgende kode, der fungerer:

int mynt = 512;
int & myRef = myInt;
int * ptr = &myInt;
int fn ()

++ptr; --ptr;
returner minInt;

Her er myInt en værdi; myRef er et udtryk for referenceværdi; * ptr er et lvalue-udtryk, fordi resultatet kan identificeres med ptr; ++ ptr eller -ptr er et lvalueudtryk, fordi resultatet kan identificeres med den nye tilstand (adresse) for ptr, og fn er et lvalue (udtryk).

Overvej følgende kodesegment:

int a = 2, b = 8;
int c = a + 16 + b + 64;

I den anden sætning har placeringen for 'a' 2 og kan identificeres med 'a', og det samme er en værdi. Placeringen for b har 8 og kan identificeres ved b, og det er også en værdi. Placeringen for c har summen og kan identificeres ved c, og det er også en værdi. I den anden sætning er udtrykkene eller værdierne på 16 og 64 værdier (se nedenfor).

Overvej følgende kodesegment:

char seq [5];
seq [0] = 'l', seq [1] = 'o', seq [2] = 'v', seq [3] = 'e', ​​seq [4] = '\ 0';
cout<< seq[2] <<'\n';

Outputtet er 'v';

seq er en matrix. Placeringen for 'v' eller en hvilken som helst lignende værdi i arrayet identificeres ved seq [i], hvor i er et indeks. Så udtrykket, seq [i], er et udtryk for en værdi. seq, som er identifikatoren for hele arrayet, er også en lvalue.

prværdi

En prværdi er et udtryk, hvis evaluering initialiserer et objekt eller et bitfelt eller beregner værdien af ​​operandens operand som specificeret af den kontekst, hvori det vises.

I erklæringen,

int myInt = 256;

256 er en prvalue (prvalue-udtryk), der initialiserer objektet identificeret af myInt. Der refereres ikke til dette objekt.

I erklæringen,

int && ref = 4;

4 er en prvalue (prvalue-udtryk), der initialiserer det objekt, der refereres til af ref. Dette objekt identificeres ikke officielt. ref er et eksempel på et r-værdi-referenceudtryk eller en pr-værdi-reference-udtryk; det er et navn, men ikke en officiel identifikator.

Overvej følgende kodesegment:

int ident;
ident = 6;
int & ref = ident;

6 er en værdi, der initialiserer objektet identificeret ved ident; objektet henvises også til med ref. Her er ref en lvalue-reference og ikke en prvalue-reference.

Overvej følgende kodesegment:

int a = 2, b = 8;
int c = a + 15 + b + 63;

15 og 63 er hver især en konstant, der beregner sig selv og producerer en operand (i bits) for additionsoperatoren. Så 15 eller 63 er et udtryk for værdien.

Enhver bogstavelig, undtagen strengen bogstavelig, er en værdi (i.e., et prævalueudtryk). Så en bogstavelig som 58 eller 58.53, eller sandt eller falsk, er en værdi. En bogstavelig kan bruges til at initialisere et objekt eller ville beregne sig selv (i en anden form i bits) som værdien af ​​en operand for en operator. I ovenstående kode initialiserer bogstavet 2 objektet, a. Det beregner sig også som en operand for opgaveoperatøren.

Hvorfor er en streng bogstavelig talt ikke en værdi? Overvej følgende kode:

char str [] = "elsker ikke had";
cout << str <<'\n';
cout << str[5] <<'\n';

Outputtet er:

elsker ikke had
n

str identificerer hele strengen. Så udtrykket str og ikke hvad det identificerer er en værdi. Hvert tegn i strengen kan identificeres ved str [i], hvor i er et indeks. Udtrykket str [5] og ikke det tegn, det identificerer, er en værdi. Strengen bogstavelig er en lvalue og ikke en prvalue.

I den følgende erklæring initialiserer en matrix bogstaveligt objektet, arr:

ptrInt ++ eller ptrInt-- 

Her er ptrInt en markør til et heltal. Hele udtrykket, og ikke den endelige værdi af den placering, det peger på, er en værdi (udtryk). Dette skyldes, at udtrykket, ptrInt ++ eller ptrInt-, identificerer den oprindelige første værdi af dens placering og ikke den anden endelige værdi af den samme placering. På den anden side er -ptrInt eller -ptrInt en lvalue, fordi den identificerer den eneste værdi af interessen i placeringen. En anden måde at se på det er, at den oprindelige værdi beregner den anden endelige værdi.

I den anden sætning af følgende kode kan a eller b stadig betragtes som en prværdi:

int a = 2, b = 8;
int c = a + 15 + b + 63;

Så, a eller b i den anden sætning er en værdi, fordi den identificerer et objekt. Det er også en værdi, da den beregner til heltalet i en operand for additionsoperatoren.

(ny int), og ikke den placering, den opretter, er en værdi. I den følgende erklæring tildeles stedets returadresse til et markørobjekt:

int * ptrInt = ny int

Her er * ptrInt en lvalue, mens (new int) er en prvalue. Husk, at en lvalue eller en prvalue er et udtryk. (new int) identificerer ikke noget objekt. At returnere adressen betyder ikke at identificere objektet med et navn (såsom ident ovenfor). I * ptrInt er navnet, ptrInt, det, der virkelig identificerer objektet, så * ptrInt er en værdi. På den anden side er (new int) en værdi, da den beregner en ny placering til en adresse med operandværdi for tildelingsoperatøren =.

xværdi

I dag står lvalue for Location Value; prvalue står for "ren" rvalue (se hvad rvalue står for nedenfor). I dag står xvalue for "eXpiring" -værdi.

Definitionen af ​​xvalue, citeret fra C ++ specifikationen, er som følger:

“En xvalue er en glvalue, der angiver et objekt eller bitfelt, hvis ressourcer kan genbruges (normalt fordi det er nær slutningen af ​​dets levetid). [Eksempel: Visse former for udtryk, der involverer rværdireferencer, giver xværdier, såsom et opkald til en funktion, hvis returtype er en rværdihenvisning eller en rollebesætning til et eksempel på rværdihenvisningstype] "

Hvad dette betyder er, at både lvalue og prvalue kan udløbe. Følgende kode (kopieret ovenfra) viser, hvordan lagring (ressource) af lvalue, * ptrInt genbruges, efter at den er blevet slettet.

int * ptrInt = ny int;
* ptrInt = 12;
cout<< *ptrInt <<'\n';
slet ptrInt;
cout<< *ptrInt <<'\n';
* ptrInt = 24;
cout<< *ptrInt <<'\n';

Outputtet er:

12
0
24

Følgende program (kopieret ovenfra) viser, hvordan lagring af et heltal, der er en referenceværdi, der returneres af en funktion, genbruges i hovedfunktionen ():

#omfatte
ved hjælp af namespace std;
int & fn ()

int i = 5;
int & j = i;
returnere j;

int main ()

int & myInt = fn ();
cout<< myInt <<'\n';
myInt = 17;
cout<< myInt <<'\n';
returnere 0;

Outputtet er:

5
17

Når et objekt som i i fn () - funktionen går uden for rækkevidde, ødelægges det naturligvis. I dette tilfælde er opbevaringen af ​​i stadig genbrugt i hovedfunktionen ().

Ovenstående to kodeeksempler illustrerer genbrug af lagring af værdier. Det er muligt at have et lager genbrug af værdier (rværdier) (se senere).

Følgende citat vedrørende xvalue er fra C ++ specifikationen:

“Generelt er virkningen af ​​denne regel, at navngivne rværdireferencer behandles som værdier, og unavngivne rværdireferencer til objekter behandles som xværdier. rværdihenvisninger til funktioner behandles som værdier, uanset om de er navngivet eller ej." (se senere).

Så en xvalue er en lvalue eller en prvalue, hvis ressourcer (lager) kan genbruges. xvalues ​​er skæringssættet af lvalues ​​og prvalues.

Der er mere at xvaluere end hvad der er behandlet i denne artikel. Imidlertid fortjener xvalue en hel artikel alene, og de ekstra specifikationer for xvalue er derfor ikke behandlet i denne artikel.

Ekspressionskategori Taxonomisæt

Et andet tilbud fra C ++ specifikationen:

Bemærk: Historisk set var værdier og værdier såkaldte, fordi de kunne vises på venstre og højre side af en opgave (selvom dette ikke længere generelt er sandt); glvaluer er "generaliserede" værdier, værdier er "rene" værdier, og xværdier er "eXpiring" -værdier. På trods af deres navne klassificerer disse udtryk udtryk, ikke værdier. - slutnote ”

Så glvalues ​​er foreningssættet af værdier og xværdier og værdier er foreningssættet af xværdier og værdier. xvalues ​​er skæringssættet af lvalues ​​og prvalues.

Fra nu af er udtrykket kategori taksonomi bedre illustreret med et Venn-diagram som følger:

Konklusion

En lvalue er et udtryk, hvis evaluering bestemmer identiteten af ​​et objekt, bitfelt eller funktion.

En prværdi er et udtryk, hvis evaluering initialiserer et objekt eller et bitfelt eller beregner værdien af ​​operandens operand som specificeret af den kontekst, hvori det vises.

En xvalue er en lvalue eller en prvalue med den yderligere egenskab, at dens ressourcer (lager) kan genbruges.

C ++ specifikationen illustrerer ekspressionskategoritaksonomi med et trædiagram, hvilket indikerer, at der er noget hierarki i taksonomien. Fra nu af er der intet hierarki i taksonomien, så et Venn-diagram bruges af nogle forfattere, da det illustrerer taksonomien bedre end trædiagrammet.

Mus Sådan vender du musens og touchpadsens rulle retning i Windows 10
Sådan vender du musens og touchpadsens rulle retning i Windows 10
Mus og Touchpads gør ikke kun computing let, men mere effektiv og mindre tidskrævende. Vi kan ikke forestille os et liv uden disse enheder, men det er...
Mus Sådan ændres musemarkør og markørstørrelse, farve og skema på Windows 10
Sådan ændres musemarkør og markørstørrelse, farve og skema på Windows 10
Musemarkøren og markøren i Windows 10 er meget vigtige aspekter af operativsystemet. Dette kan også siges om andre operativsystemer, så i sandhed er d...
Gratis og open source-spilmotorer til udvikling af Linux-spil
Denne artikel dækker en liste over gratis og open source-spilmotorer, der kan bruges til at udvikle 2D- og 3D-spil på Linux. Der er mange sådanne spil...