C ++

Taksonomija kategorije izrazov v jeziku C ++

Taksonomija kategorije izrazov v jeziku C ++

Izračun je katera koli vrsta izračuna, ki sledi natančno določenemu algoritmu. Izraz je zaporedje operatorjev in operandov, ki določa izračun. Z drugimi besedami, izraz je identifikator ali dobesedno besedilo ali zaporedje obeh, ki jih združijo operaterji.Pri programiranju lahko izraz povzroči vrednost in / ali povzroči nekaj dogodkov. Ko ima za posledico vrednost, je izraz glvalue, rvalue, lvalue, xvalue ali prvalue. Vsaka od teh kategorij je niz izrazov. Vsak sklop ima definicijo in posebne situacije, ko prevlada njegov pomen, kar ga razlikuje od drugega niza. Vsak niz se imenuje vrednostna kategorija.

Opomba: Vrednost ali dobesedno besedilo je še vedno izraz, zato ti izrazi razvrščajo izraze in ne zares vrednosti.

glvalue in rvalue sta dve podmnožici iz izraza velikega niza. glvalue obstaja v dveh nadaljnjih podnaborih: lvalue in xvalue. rvalue, druga podmnožica za izraz, obstaja tudi v dveh nadaljnjih podnaborih: xvalue in prvalue. Torej, xvalue je podmnožica glvalue in rvalue: to pomeni, da je xvalue presečišče glvalue in rvalue. Naslednji taksonomski diagram, vzet iz specifikacije C ++, ponazarja odnos vseh nizov:

prvalue, xvalue in lvalue so vrednosti primarne kategorije. glvalue je zveza lvalues ​​in xvalues, medtem ko je rvalues ​​unija xvalues ​​in prvalues.

Za razumevanje tega članka potrebujete osnovno znanje jezika C ++; potrebujete tudi znanje področja uporabe v jeziku C++.

Vsebina članka

Osnove

Če želite resnično razumeti taksonomijo kategorij izrazov, morate najprej priklicati ali poznati naslednje osnovne značilnosti: lokacijo in objekt, pomnilnik in vir, inicializacijo, identifikator in sklic, sklice lvalue in rvalue, kazalec, prosto shranjevanje in ponovno uporabo vir.

Lokacija in objekt

Upoštevajte naslednjo izjavo:

int ident;

To je izjava, ki identificira lokacijo v spominu. Lokacija je določen niz zaporednih bajtov v pomnilniku. Lokacija je lahko sestavljena iz enega bajta, dveh bajtov, štirih bajtov, štiriinšestdesetih bajtov itd. Mesto za celo število za 32-bitni stroj je štiri bajte. Tudi lokacijo je mogoče identificirati z identifikatorjem.

V zgornji izjavi lokacija nima nobene vsebine. Pomeni, da nima nobene vrednosti, saj je vsebina vrednost. Torej, identifikator identificira lokacijo (majhen neprekinjen prostor). Ko je lokaciji dana določena vsebina, identifikator nato identificira tako lokacijo kot vsebino; to pomeni, da identifikator nato identificira lokacijo in vrednost.

Upoštevajte naslednje trditve:

int ident1 = 5;
int ident2 = 100;

Vsaka od teh izjav je izjava in definicija. Prvi identifikator ima vrednost (vsebina) 5, drugi identifikator pa vrednost 100. V 32-bitnem stroju je vsaka od teh lokacij dolga štiri bajte. Prvi identifikator identificira lokacijo in vrednost. Drugi identifikator prav tako identificira oba.

Predmet je imenovano območje shranjevanja v pomnilniku. Torej je objekt bodisi lokacija brez vrednosti bodisi lokacija z vrednostjo.

Shramba in viri predmetov

Lokacija predmeta se imenuje tudi pomnilnik ali vir predmeta.

Inicializacija

Upoštevajte naslednji segment kode:

int ident;
ident = 8;

Prva vrstica označuje identifikator. Ta izjava zagotavlja lokacijo (pomnilnik ali vir) za celoštevilski objekt, ki ga identificira z imenom, ident. Naslednja vrstica postavi vrednost 8 (v bitih) na mesto, ki ga označuje ident. Dajanje te vrednosti je inicializacija.

Naslednja izjava definira vektor z vsebino 1, 2, 3, 4, 5, ki jo označuje vtr:

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

Tu se inicializacija z 1, 2, 3, 4, 5 izvede v istem stavku definicije (deklaracije). Operator dodelitve se ne uporablja. Naslednja izjava definira matriko z vsebino 1, 2, 3, 4, 5:

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

Tokrat je bil za inicializacijo uporabljen operater dodelitve.

Identifikator in referenca

Upoštevajte naslednji segment kode:

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

Rezultat je:

4 4 4

ident je identifikator, medtem ko sta ref1 in ref2 sklici; sklicujejo se na isto lokacijo. Referenca je sinonim za identifikator. Običajno sta ref1 in ref2 različni imeni enega predmeta, medtem ko je ident identifikator istega predmeta. Vendar lahko ident še vedno imenujemo ime predmeta, kar pomeni, da ident, ref1 in ref2 imenujeta isto lokacijo.

Glavna razlika med identifikatorjem in sklicem je v tem, da se ob predaji kot argument funkciji, če se posreduje z identifikatorjem, naredi kopija identifikatorja v funkciji, medtem ko se, če jo posreduje referenca, isto mesto uporabi v funkcijo. Torej, prenos mimo identifikatorja konča na dveh lokacijah, medtem ko mimoidoč sklic konča na isti lokaciji.

referenca lvalue in referenca rvalue

Običajni način ustvarjanja sklica je naslednji:

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

Najprej se poišče in identificira pomnilnik (vir) (nato z imenom, kot je ident), nato pa se naredi sklic (z imenom, kot je sklic). Ko se funkcija prenese kot argument, bo v funkciji narejena kopija identifikatorja, v primeru sklica pa bo v funkciji uporabljena (navedena) izvirna lokacija.

Danes je mogoče samo imeti referenco, ne da bi jo identificirali. To pomeni, da je mogoče najprej ustvariti referenco, ne da bi imeli identifikator lokacije. Ta uporablja &&, kot je prikazano v naslednji izjavi:

int && ref = 4;

Tu ni predhodne identifikacije. Če želite dostopati do vrednosti predmeta, preprosto uporabite ref, kot bi uporabili zgornji ident.

Z izjavo && ni možnosti posredovanja argumenta funkciji z identifikatorjem. Edina izbira je podajanje po referenci. V tem primeru je v funkciji uporabljeno samo eno mesto in ne drugo kopirano mesto kot pri identifikatorju.

Referenčna izjava z & se imenuje referenca lvalue. Referenčna izjava z && se imenuje referenca rvalue, ki je tudi referenca prvalue (glej spodaj).

Kazalec

Upoštevajte naslednjo kodo:

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

Izhod je 5.

Tu je ptdInt identifikator, kot je ident zgoraj. Tu sta namesto enega dva predmeta (lokacije): koničasti objekt, ptdInt, ki ga identificira ptdInt, in kazalec, ptrInt, ki ga identificira ptrInt. & ptdInt vrne naslov koničastega predmeta in ga postavi kot vrednost v predmetu kazalca ptrInt. Če želite vrniti (pridobiti) vrednost usmerjenega predmeta, uporabite identifikator kazalnega predmeta, kot v “* ptrInt”.

Opomba: ptdInt je identifikator in ne referenca, medtem ko je ime, ref, omenjeno prej, referenca.

Drugo in tretjo vrstico v zgornji kodi je mogoče zmanjšati na eno vrstico, kar vodi do naslednje kode:

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

Opomba: Ko se kazalnik poveča, kaže na naslednjo lokacijo, ki ni dodatek vrednosti 1. Ko se kazalnik zmanjša, kaže na prejšnjo lokacijo, kar ni odštevanje vrednosti 1.

Brezplačna trgovina

Operacijski sistem dodeli pomnilnik za vsak program, ki se izvaja. Spomin, ki ni dodeljen nobenemu programu, je znan kot brezplačna shramba. Izraz, ki vrne lokacijo za celo število iz brezplačne trgovine, je:

nov int

To vrne lokacijo za celo število, ki ni identificirano. Naslednja koda ponazarja, kako uporabljati kazalnik v brezplačni trgovini:

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

Izhod je 12.

Če želite uničiti predmet, uporabite izraz za brisanje na naslednji način:

izbriši ptrInt;

Argument izraza za brisanje je kazalec. Naslednja koda ponazarja njegovo uporabo:

int * ptrInt = novo int;
* ptrInt = 12;
izbriši ptrInt;
cout<< *ptrInt <<'\n';

Izhod je 0, in ne nič takega kot nič ali nedefinirano. delete nadomesti vrednost za lokacijo s privzeto vrednostjo določene vrste lokacije, nato pa omogoči lokacijo za ponovno uporabo. Privzeta vrednost za int lokacijo je 0.

Ponovna uporaba vira

V taksonomiji kategorij izrazov je ponovna uporaba vira enaka ponovni uporabi lokacije ali shrambe za objekt. Naslednja koda prikazuje, kako lahko lokacijo iz brezplačne trgovine ponovno uporabimo:

int * ptrInt = novo int;
* ptrInt = 12;
cout<< *ptrInt <<'\n';
izbriši ptrInt;
cout<< *ptrInt <<'\n';
* ptrInt = 24;
cout<< *ptrInt <<'\n';

Rezultat je:

12
0
24

Neznani lokaciji se najprej dodeli vrednost 12. Nato se vsebina lokacije izbriše (v teoriji se objekt izbriše). Vrednost 24 je znova dodeljena isti lokaciji.

Naslednji program prikazuje, kako se celoštevilčna referenca, ki jo vrne funkcija, ponovno uporabi:

#include
uporaba imenskega prostora std;
int & fn ()

int i = 5;
int & j = i;
vrnitev j;

int main ()

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

Rezultat je:

5
17

Objekt, kot je i, prijavljen v lokalnem obsegu (obseg funkcije), preneha obstajati na koncu lokalnega obsega. Vendar funkcija fn () vrne sklic na i. Skozi to vrnjeno referenco ime myInt v funkciji main () ponovno uporabi lokacijo, določeno z i za vrednost 17.

Vrednost

Vrednost l je izraz, katerega vrednotenje določa identiteto predmeta, bitnega polja ali funkcije. Identiteta je uradna identiteta, kot je ident zgoraj, ali referenčno ime lvalue, kazalec ali ime funkcije. Upoštevajte naslednjo kodo, ki deluje:

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

++ptr; --ptr;
vrni myInt;

Tukaj je myInt vrednost; myRef je referenčni izraz lvalue; * ptr je izraz lvalue, ker je njegov rezultat mogoče identificirati s ptr; ++ ptr ali -ptr je izraz lvalue, ker je njegov rezultat mogoče identificirati z novim stanjem (naslovom) ptr, fn pa je lvalue (izraz).

Upoštevajte naslednji segment kode:

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

V drugi izjavi ima lokacija za 'a' 2 in jo je mogoče prepoznati z 'a', prav tako pa je tudi lvalue. Mesto za b ima 8 in ga je mogoče prepoznati z b, pa tudi vrednost l. Lokacija za c bo imela vsoto in jo je mogoče prepoznati s c, prav tako pa tudi vrednost l. V drugem stavku so izrazi ali vrednosti 16 in 64 vrednosti r (glej spodaj).

Upoštevajte naslednji segment kode:

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

Rezultat je 'v';

seq je matrika. Mesto za 'v' ali katero koli podobno vrednost v matriki je označeno s seq [i], kjer je i indeks. Torej je izraz seq [i] izraz lvalue. seq, ki je identifikator celotne matrike, je tudi vrednost.

prvalue

Prvalue je izraz, katerega vrednotenje inicializira objekt ali bitno polje ali izračuna vrednost operanda operaterja, kot je določeno v kontekstu, v katerem se pojavi.

V izjavi,

int myInt = 256;

256 je prvalue (izraz prvalue), ki inicializira objekt, ki ga identificira myInt. Ta predmet ni sklican.

V izjavi,

int && ref = 4;

4 je prva vrednost (izraz prva vrednost), ki inicializira predmet, na katerega se sklicuje ref. Ta predmet ni uradno identificiran. ref je primer referenčnega izraza rvalue ali referenčnega izraza prvalue; to je ime, ne pa tudi uradna identifikacija.

Upoštevajte naslednji segment kode:

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

6 je prva vrednost, ki inicializira objekt, identificiran z ident; na predmet se sklicuje tudi ref. Tu je ref referenca lvalue in ne referenca prvalue.

Upoštevajte naslednji segment kode:

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

15 in 63 sta vsaka konstanta, ki izračuna sama zase in ustvari operand (v bitih) za operater seštevanja. Torej, 15 ali 63 je izraz prve vrednosti.

Vsaka dobesedna črka, razen nizovne, je prva vrednost (tj.e., izraz prve vrednosti). Torej, dobesedno besedilo, kot je 58 ali 58.53, ali res ali ne, je prva vrednost. Dobesedno besedilo lahko uporabimo za inicializiranje predmeta ali pa bi izračunali zase (v drugo obliko v bitov) kot vrednost operanda za operaterja. V zgornji kodi slovnica 2 inicializira objekt, a. Prav tako se izračuna kot operand za operater dodelitve.

Zakaj nizovna dobesedna črka ni prva vrednost? Upoštevajte naslednjo kodo:

char str [] = "ljubezen ne sovraštvo";
cout << str <<'\n';
cout << str[5] <<'\n';

Rezultat je:

ljubezen ne sovraštvo
n

str identificira celoten niz. Torej je izraz str in ne tisto, kar identificira, vrednost. Vsak znak v nizu je mogoče prepoznati po str [i], kjer je i indeks. Izraz str [5] in ne znak, ki ga identificira, je vrednost l. Niz literala je vrednost l in ne prva vrednost.

V naslednjem stavku matrika literal inicializira objekt, arr:

ptrInt ++ ali ptrInt-- 

Tu je ptrInt kazalec na celoštevilčno lokacijo. Celoten izraz in ne končna vrednost lokacije, na katero kaže, je prva vrednost (izraz). To je zato, ker izraz, ptrInt ++ ali ptrInt-, identificira prvotno prvo vrednost svoje lokacije in ne drugo končno vrednost iste lokacije. Po drugi strani pa je -ptrInt ali -ptrInt vrednost l, ker opredeljuje edino vrednost obresti na lokaciji. Drug način gledanja je, da prvotna vrednost izračuna drugo končno vrednost.

V drugem stavku naslednje kode lahko a ali b še vedno štejemo za prvo vrednost:

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

Torej je a ali b v drugem stavku vrednost l, ker identificira objekt. Je tudi prva vrednost, saj izračuna operaterju seštevanja na celo število operanda.

(new int) in ne lokacija, ki jo vzpostavi, je prva vrednost. V naslednjem stavku je predmetu kazalca dodeljen povratni naslov lokacije:

int * ptrInt = novo int

Tu je * ptrInt vrednost, medtem ko je (novo int) prva vrednost. Ne pozabite, da je vrednost l ali vrednost prva vrednost. (new int) ne prepozna nobenega predmeta. Vrnitev naslova ne pomeni identifikacije predmeta z imenom (na primer ident zgoraj). V * ptrInt je ime ptrInt tisto, kar resnično identificira predmet, zato je * ptrInt vrednost l. Po drugi strani pa je (new int) prva vrednost, saj izračuna novo lokacijo na naslov vrednosti operanda za operater dodelitve =.

xvalue

Danes lvalue pomeni Lokacijska vrednost; prvalue pomeni "čisto" vrednost (glejte, kaj pomeni vrednost rvalue spodaj). Danes xvalue pomeni "eXpiring" lvalue.

Definicija xvalue, navedena v specifikaciji C ++, je naslednja:

»Xvalue je glvalue, ki označuje objekt ali bitno polje, katerega vire je mogoče ponovno uporabiti (običajno zato, ker je blizu konca življenjske dobe). [Primer: Nekatere vrste izrazov, ki vključujejo sklice na vrednost rvalue, dajo vrednosti x, na primer klic funkcije, katere vrnjeni tip je referenca na vrednost ali oddaja na primer konca vrste reference referenčne vrednosti] "

To pomeni, da lahko lvalue in prvalue potečeta. Naslednja koda (kopirana od zgoraj) prikazuje, kako se shramba (vir) lvalue, * ptrInt ponovno uporabi, potem ko je bila izbrisana.

int * ptrInt = novo int;
* ptrInt = 12;
cout<< *ptrInt <<'\n';
izbriši ptrInt;
cout<< *ptrInt <<'\n';
* ptrInt = 24;
cout<< *ptrInt <<'\n';

Rezultat je:

12
0
24

Naslednji program (kopiran od zgoraj) prikazuje, kako se v funkciji main () ponovno uporabi shranjevanje celoštevilčne reference, ki je referenca lvalue, ki jo vrne funkcija:

#include
uporaba imenskega prostora std;
int & fn ()

int i = 5;
int & j = i;
vrnitev j;

int main ()

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

Rezultat je:

5
17

Ko objekt, kot je i v funkciji fn (), izstopi iz obsega, se seveda uniči. V tem primeru je bilo shranjevanje i še vedno ponovno uporabljeno v glavni () funkciji.

Zgornja dva vzorca kode ponazarjata ponovno uporabo shrambe vrednosti. Možno je, da shramba ponovno uporabi vrednosti (vrednosti) (glej kasneje).

Naslednji citat glede xvalue je iz specifikacije C ++:

»Na splošno je učinek tega pravila, da se poimenovani sklici na vrednost obravnavajo kot vrednosti, neimenovana sklicevanja na vrednosti pa na predmete kot vrednosti. Sklici rvalue na funkcije se obravnavajo kot vrednosti l, poimenovane ali ne."(Glej kasneje).

Torej, xvalue je vrednost ali prva vrednost, katere vire (pomnilnik) je mogoče ponovno uporabiti. xvalues ​​je presečišče množic lvalues ​​in prvalues.

Xvalue je več kot to, kar je obravnavano v tem članku. Vendar pa si xvalue zasluži celoten članek sam, zato dodatne zahteve za xvalue v tem članku niso obravnavane.

Nabor taksonomije kategorije izraza

Še en citat iz specifikacije C ++:

Opomba: V preteklosti so bile vrednosti in vrednote tako imenovane, ker so se lahko pojavile na levi in ​​desni strani naloge (čeprav to na splošno ne drži več); glvalues ​​so "splošne" vrednosti, prvalues ​​so "čiste" rvalues, xvalues ​​pa "eXpiring" lvalues. Kljub svojim imenom ti izrazi uvrščajo izraze in ne vrednosti. - končna opomba "

Torej, glvalues ​​je zvezna množica lvalues ​​in xvalues ​​in rvalues ​​je unija nabor xvalues ​​in prvalues. xvalues ​​je presečišče množic lvalues ​​in prvalues.

Od zdaj je taksonomija kategorij izrazov bolje ponazorjena z Vennovim diagramom, kot sledi:

Zaključek

Vrednost l je izraz, katerega vrednotenje določa identiteto predmeta, bitnega polja ali funkcije.

Prvalue je izraz, katerega vrednotenje inicializira objekt ali bitno polje ali izračuna vrednost operanda operaterja, kot je določeno v kontekstu, v katerem se pojavi.

Xvalue je lvalue ali prvalue z dodatno lastnostjo, da je mogoče njegove vire (pomnilnik) ponovno uporabiti.

Specifikacija C ++ ponazarja taksonomijo kategorij izrazov z drevesnim diagramom, ki kaže, da je v taksonomiji nekaj hierarhije. Zdaj v taksonomiji ni hierarhije, zato nekateri avtorji uporabljajo Vennov diagram, saj taksonomijo ponazarja bolje kot drevesni diagram.

Kako obrniti smer drsenja miške in sledilne ploščice v sistemu Windows 10
Miška in Sledilna ploščicaRačunalništvo ni samo enostavno, ampak bolj učinkovito in manj zamudno. Življenja brez teh naprav si ne moremo predstavljati...
Kako spremeniti miškin kazalec in velikost, barvo in shemo kazalca v sistemu Windows 10
Kazalec miške in kazalec v operacijskem sistemu Windows 10 sta zelo pomembna vidika operacijskega sistema. To lahko rečemo tudi za druge operacijske s...
Brezplačni in odprtokodni igralni mehanizmi za razvoj iger Linux
Ta članek bo zajemal seznam brezplačnih in odprtokodnih igralnih mehanizmov, ki jih je mogoče uporabiti za razvoj 2D in 3D iger v Linuxu. Obstaja veli...