C ++

Išraiškos kategorijos taksonomija C ++

Išraiškos kategorijos taksonomija C ++

Skaičiavimas yra bet kokio tipo skaičiavimas, atliekamas pagal tiksliai apibrėžtą algoritmą. Išraiška yra operatorių ir operandų seka, nurodanti skaičiavimą. Kitaip tariant, išraiška yra identifikatorius arba literalas, arba abiejų seka, sujungta operatorių.Programuojant išraiška gali atsirasti reikšmė ir (arba) sukelti tam tikrus įvykius. Kai gaunama reikšmė, išraiška yra glvalue, rvalue, lvalue, xvalue arba prvalue. Kiekviena iš šių kategorijų yra išraiškų rinkinys. Kiekvienas rinkinys turi apibrėžimą ir konkrečias situacijas, kai vyrauja jo reikšmė, išskiriant jį iš kito rinkinio. Kiekvienas rinkinys vadinamas vertės kategorija.

Pastaba: Vertė arba pažodinis žodis vis dar yra išraiška, todėl šie terminai klasifikuoja išraiškas, o ne iš tikrųjų vertybes.

glvalue ir rvalue yra du pogrupiai iš didžiosios aibės išraiškos. glvalue egzistuoja dar dviejuose pogrupiuose: lvalue ir xvalue. rvalue, kitas išraiškos pogrupis, taip pat egzistuoja dar dviejuose pogrupiuose: xvalue ir prvalue. Taigi, xvalue yra tiek glvalue, tiek rvalue pogrupis: ty xvalue yra tiek glvalue, tiek rvalue sankirta. Ši taksonomijos diagrama, paimta iš C ++ specifikacijos, iliustruoja visų rinkinių ryšį:

prvalue, xvalue ir lvalue yra pagrindinės kategorijos vertės. glvalue yra lvalues ​​ir xvalues, o rvalues ​​yra xvalues ​​ir prvalues ​​jungtis.

Jums reikia pagrindinių žinių C ++ kalba, kad suprastumėte šį straipsnį; jums taip pat reikia žinių apie taikymo sritį C++.

Straipsnio turinys

Pagrindai

Norint iš tikrųjų suprasti frazės kategorijos taksonomiją, pirmiausia turite prisiminti arba žinoti šias pagrindines savybes: vietą ir objektą, saugyklą ir išteklius, inicializavimą, identifikatorių ir nuorodą, lvalue ir rvalue nuorodas, žymiklį, nemokamą saugyklą ir pakartotinį išteklių.

Vieta ir objektas

Apsvarstykite šią deklaraciją:

int ident;

Tai deklaracija, nurodanti vietą atmintyje. Vieta yra tam tikras nuoseklių baitų rinkinys atmintyje. Vietą gali sudaryti vienas baitas, du baitai, keturi baitai, šešiasdešimt keturi baitai ir kt. 32 bitų mašinos sveiko skaičiaus vieta yra keturi baitai. Be to, vietą galima identifikuoti pagal identifikatorių.

Pirmiau pateiktoje deklaracijoje vieta neturi jokio turinio. Tai reiškia, kad jis neturi jokios vertės, nes turinys yra vertė. Taigi, identifikatorius identifikuoja vietą (nedidelę ištisinę erdvę). Kai vietai suteikiamas konkretus turinys, identifikatorius identifikuoja ir vietą, ir turinį; tai yra, tada identifikatorius identifikuoja ir vietą, ir vertę.

Apsvarstykite šiuos teiginius:

int ident1 = 5;
int ident2 = 100;

Kiekvienas iš šių teiginių yra deklaracija ir apibrėžimas. Pirmojo identifikatoriaus vertė (turinys) yra 5, o antrojo - 100. 32 bitų mašinoje kiekviena iš šių vietų yra keturių baitų ilgio. Pirmasis identifikatorius identifikuoja ir vietą, ir vertę. Antrasis identifikatorius taip pat identifikuoja abu.

Objektas yra įvardytas atminties regionas. Taigi objektas yra arba vieta be vertės, arba vieta su verte.

Objekto saugojimas ir šaltinis

Objekto vieta taip pat vadinama objekto saugykla ar ištekliu.

Inicijavimas

Apsvarstykite šį kodo segmentą:

int ident;
ident = 8;

Pirmoje eilutėje nurodomas identifikatorius. Šioje deklaracijoje nurodoma sveiko skaičiaus objekto vieta (saugykla ar išteklius), identifikuojant jį pavadinimu, identifikatoriumi. Kitoje eilutėje vertė 8 (bitais) įtraukiama į identifikuojamą vietą. Šios vertės pateikimas yra inicijavimas.

Šis sakinys apibrėžia vektorių, kurio turinys yra 1, 2, 3, 4, 5, identifikuojamas pagal vtr:

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

Čia inicialas su 1, 2, 3, 4, 5 atliekamas tame pačiame apibrėžimo (deklaracijos) sakinyje. Priskyrimo operatorius nenaudojamas. Šis sakinys apibrėžia masyvą su turiniu 1, 2, 3, 4, 5:

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

Šį kartą inicijavimui buvo naudojamas priskyrimo operatorius.

Identifikatorius ir nuoroda

Apsvarstykite šį kodo segmentą:

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

Rezultatas yra:

4 4 4

ident yra identifikatorius, o ref1 ir ref2 yra nuorodos; jie nurodo tą pačią vietą. Nuoroda yra identifikatoriaus sinonimas. Paprastai „ref1“ ir „ref2“ yra skirtingi vieno objekto pavadinimai, o „ident“ yra to paties objekto identifikatorius. Tačiau „ident“ vis tiek galima vadinti objekto pavadinimu, kuris reiškia, ident, ref1 ir ref2 pavadinkite tą pačią vietą.

Pagrindinis skirtumas tarp identifikatoriaus ir nuorodos yra tas, kad perduodant funkciją kaip argumentą, jei perduodamas identifikatoriumi, funkcijoje esančiam identifikatoriui daroma kopija, o jei perduota pagal nuorodą, ta pati vieta naudojama funkcija. Taigi, praeinant pagal identifikatorių, yra dvi vietos, o einant per nuorodą - ta pati vieta.

lvalue nuoroda ir rvalue nuoroda

Normalus būdas sukurti nuorodą yra toks:

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

Pirmiausia randama ir identifikuojama saugykla (išteklius) (su pavadinimu, pvz., Identifikatoriumi), tada daroma nuoroda (su pavadinimu, pvz., Nuoroda). Perduodant kaip argumentą funkcijai, funkcijoje bus padaryta identifikatoriaus kopija, o nuorodos atveju funkcijoje bus naudojama (nurodyta) originali vieta.

Šiandien galima tiesiog turėti nuorodą jos nenustačius. Tai reiškia, kad pirmiausia galima sukurti nuorodą neturint vietos identifikatoriaus. Tam naudojama &&, kaip parodyta šiame sakinyje:

int && ref = 4;

Čia nėra ankstesnio identifikavimo. Norėdami pasiekti objekto vertę, tiesiog naudokite nuorodą taip, kaip naudotumėte aukščiau nurodytą identifikatorių.

Su && deklaracija nėra galimybės perduoti argumento funkcijai pagal identifikatorių. Vienintelis pasirinkimas yra perduoti nuorodą. Šiuo atveju funkcijoje naudojama tik viena vieta, o ne antroji nukopijuota vieta kaip su identifikatoriumi.

Nuorodos deklaracija su & vadinama lvalue nuoroda. Nuorodos deklaracija su && vadinama rvalue nuoroda, kuri taip pat yra prvalue nuoroda (žr. Toliau).

Rodyklė

Apsvarstykite šį kodą:

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

Rezultatas yra 5.

Čia „ptdInt“ yra identifikatorius, panašus į aukščiau pateiktą. Čia yra du objektai (vietovės), o ne vienas: smailus objektas, ptdInt, identifikuojamas ptdInt, ir rodyklės objektas ptrInt, identifikuojamas ptrInt. & ptdInt grąžina smailaus objekto adresą ir įtraukia jį kaip reikšmę į rodyklės ptrInt objektą. Norėdami grąžinti (gauti) smailaus objekto vertę, naudokite žymeklio objekto identifikatorių, kaip nurodyta „* ptrInt“.

Pastaba: ptdInt yra identifikatorius, o ne nuoroda, o anksčiau paminėtas pavadinimas ref.

Antrą ir trečią aukščiau minėto kodo eilutes galima sutrumpinti iki vienos eilutės, todėl gaunamas šis kodas:

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

Pastaba: Kai rodyklė yra padidinta, ji nurodo kitą vietą, kuri nėra 1 vertės pridėjimas. Kai žymeklis mažinamas, jis nurodo ankstesnę vietą, kuri nėra 1 vertės atimtis.

Nemokama parduotuvė

Operacinė sistema paskirsto atmintį kiekvienai vykdomai programai. Atmintis, kuri nėra skirta jokiai programai, vadinama nemokama parduotuve. Išraiška, kuri grąžina sveiko skaičiaus vietą iš nemokamos parduotuvės, yra:

naujas tarpt

Tai grąžina nenustatyto sveikojo skaičiaus vietą. Šis kodas parodo, kaip naudoti žymeklį su nemokama parduotuve:

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

Rezultatas yra 12.

Norėdami sunaikinti objektą, naudokite ištrynimo išraišką taip:

ištrinti ptrInt;

Ištrynimo išraiškos argumentas yra rodyklė. Šis kodas iliustruoja jo naudojimą:

int * ptrInt = naujas int;
* ptrInt = 12;
ištrinti ptrInt;
cout<< *ptrInt <<'\n';

Rezultatas yra 0, ir nieko panašaus į nieką ar neapibrėžtą. „delete“ pakeičia vietovės vertę numatytąja tam tikro tipo vietovės verte, tada leidžia vietą naudoti dar kartą. Numatytoji int vietos reikšmė yra 0.

Pakartotinis išteklių naudojimas

Išraiškos kategorijos taksonomijoje išteklių naudojimas yra tas pats, kas objekto vietos ar saugyklos pakartotinis naudojimas. Šis kodas parodo, kaip galima nemokamai naudoti vietą iš nemokamos parduotuvės:

int * ptrInt = naujas int;
* ptrInt = 12;
cout<< *ptrInt <<'\n';
ištrinti ptrInt;
cout<< *ptrInt <<'\n';
* ptrInt = 24;
cout<< *ptrInt <<'\n';

Rezultatas yra:

12
0
24

Pirmiausia nenustatytai vietai priskiriama 12 reikšmė. Tada vietovės turinys ištrinamas (teoriškai objektas ištrinamas). 24 reikšmė vėl priskiriama tai pačiai vietai.

Ši programa parodo, kaip pakartotinai naudojama funkcijos grąžinta sveiko skaičiaus nuoroda:

# įtraukti
naudojant vardų sritį std;
int & fn ()

int i = 5;
int & j = i;
grįžti j;

int main ()

int & myInt = fn ();
cout<< myInt <<'\n';
myInt = 17;
cout<< myInt <<'\n';
grąžinti 0;

Rezultatas yra:

5
17

Objektas, pvz., I, paskelbtas vietine apimtimi (funkcijos sritimi), nustoja egzistuoti vietinės srities pabaigoje. Tačiau aukščiau pateikta funkcija fn () pateikia i nuorodą. Naudodamas šią grąžintą nuorodą, pavadinimas, myInt, esantis pagrindinėje () funkcijoje, pakartotinai naudoja vietą, kurią i identifikuoja kaip reikšmę 17.

vertė

Lvalue yra išraiška, kurios įvertinimas nustato objekto, bitų lauko ar funkcijos tapatumą. Tapatybė yra oficiali tapatybė, pvz., Tapatybė viršuje, arba lvalue nuorodos vardas, rodyklė ar funkcijos pavadinimas. Apsvarstykite šį veikiantį kodą:

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

++ptr; --ptr;
grąžinti myInt;

Čia myInt yra vertė; myRef yra lvalue nuorodos išraiška; * ptr yra reikšmės išraiška, nes jo rezultatas identifikuojamas su ptr; ++ ptr arba -ptr yra lvalue išraiška, nes jo rezultatas gali būti identifikuojamas su nauja ptr būsena (adresu), o fn yra lvalue (išraiška).

Apsvarstykite šį kodo segmentą:

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

Antrame sakinyje „a“ vieta turi 2 ir ją galima identifikuoti pagal „a“, taip pat yra ir vertė. B vietoje yra 8, ją galima atpažinti pagal b, taigi ir vertę. C vieta turės sumą, ją galima atpažinti pagal c, taigi ir lvalue. Antrame teiginyje 16 ir 64 išraiškos arba reikšmės yra vertės (žr. Toliau).

Apsvarstykite šį kodo segmentą:

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

Rezultatas yra 'v";

sek yra masyvas. „V“ ar bet kurios panašios masyvo vertės vieta identifikuojama seka [i], kur i yra indeksas. Taigi išraiška, seq [i], yra vertės reikšmė. seq, kuris yra viso masyvo identifikatorius, taip pat yra lvalue.

prvalue

Prvalue yra išraiška, kurios įvertinimas inicijuoja objektą ar bitų lauką arba apskaičiuoja operatoriaus operando vertę, kaip nurodyta kontekste, kuriame ji rodoma.

Pareiškime,

int myInt = 256;

256 yra prvalue (prvalue išraiška), kuri inicijuoja „myInt“ identifikuotą objektą. Šis objektas nenurodytas.

Pareiškime,

int && ref = 4;

4 yra prvalue (prvalue išraiška), kuri inicijuoja objektą, nurodytą nuorodoje. Šis objektas nėra oficialiai nustatytas. ref yra rvalue nuorodos išraiškos arba prvalue referencinės išraiškos pavyzdys; tai vardas, bet ne oficialus identifikatorius.

Apsvarstykite šį kodo segmentą:

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

6 yra prvalue, kuri inicijuoja objektą, identifikuojamą identifikuojant; objektą taip pat nurodo nuoroda. Čia nuoroda yra lvalue nuoroda, o ne prvalue nuoroda.

Apsvarstykite šį kodo segmentą:

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

15 ir 63 yra konstanta, kuri apskaičiuoja pati save, sukuria operandą (bitais) pridėjimo operatoriui. Taigi, 15 arba 63 yra prvalue išraiška.

Bet koks pažodinis, išskyrus eilutės literalį, yra prvalue (t.e., prvalue išraiška). Taigi, pažodinis, pavyzdžiui, 58 ar 58.53 arba teisinga ar melaginga yra prvalue. Pažodinis gali būti naudojamas objektui inicializuoti arba būtų apskaičiuojamas pats sau (į kitą formą bitais) kaip operando reikšmę operatoriui. Pirmiau pateiktame kode pažodinis 2 inicializuoja objektą, a. Tai taip pat priskiria save operacijos priskyrimo operatoriui.

Kodėl eilutė tiesiogine prasme nėra prvalue? Apsvarstykite šį kodą:

char str [] = "nemylėk meilės";
cout << str <<'\n';
cout << str[5] <<'\n';

Rezultatas yra:

myliu neapykantą
n

str identifikuoja visą eilutę. Taigi išraiška „str“, o ne tai, ką ji identifikuoja, yra vertė. Kiekvieną eilutės simbolį galima atpažinti iš str [i], kur i yra rodyklė. Išraiška str [5], o ne jos identifikuojamas simbolis yra vertė. String literal yra vertė, o ne prvalue.

Šiame sakinyje masyvas pažodžiui inicijuoja objektą arr:

„ptrInt ++“ arba „ptrInt“-- 

Čia „ptrInt“ yra rodiklis į sveiko skaičiaus vietą. Visa išraiška, o ne galutinė vietos, į kurią nurodo, vertė yra prvalue (išraiška). Taip yra todėl, kad išraiška „ptrInt ++“ arba „ptrInt-“ identifikuoja pradinę pirmąją jos vietos vertę, o ne antrąją galutinę tos pačios vietos vertę. Kita vertus, -ptrInt arba -ptrInt yra vertė, nes ji nurodo vienintelę domėjimosi vieta vertę. Kitas būdas į tai žiūrėti yra tai, kad pradinė vertė apskaičiuoja antrąją galutinę vertę.

Antrame šio kodo sakinyje a arba b vis tiek gali būti laikomi prvalue:

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

Taigi, a arba b antrame sakinyje yra vertė, nes identifikuoja objektą. Tai taip pat yra prvalue, nes ji apskaičiuojama pagal operacijos skaičių, esantį pridėjimo operatoriui.

(nauja int), o ne vieta, kurią nustato, yra prvalue. Šiame sakinyje grąžinimo vietos adresas priskiriamas žymeklio objektui:

int * ptrInt = naujas int

Čia * ptrInt yra lvalue, o (new int) yra prvalue. Atminkite, kad lvalue arba prvalue yra išraiška. (naujas int) nenustato jokio objekto. Adreso grąžinimas nereiškia objekto identifikavimo pavadinimu (pvz., Tapatybė, aukščiau). * PtrInt, pavadinimas ptrInt yra tas, kuris iš tikrųjų identifikuoja objektą, taigi * ptrInt yra lvalue. Kita vertus, (naujas int) yra prvalue, nes jis priskyrimo operatoriui apskaičiuoja naują vietą operando vertės adresu =.

xvalue

Šiandien „lvalue“ reiškia „Vietos vertė“; prvalue reiškia „gryną“ rvalue (žemiau pažiūrėkite, ką reiškia rvalue). Šiandien xvalue reiškia „eXpiring“ lvalue.

„Xvalue“ apibrėžimas, cituojamas iš C ++ specifikacijos, yra toks:

„Xvalue yra glvalue, žyminti objektą ar bitų lauką, kurio išteklius galima pakartotinai naudoti (paprastai todėl, kad jis beveik baigiasi savo gyvenimo trukme). [Pavyzdys: Tam tikros rūšies išraiškos, susijusios su nuorodomis į reikšmes, suteikia x reikšmes, pvz., Iškvietimas į funkciją, kurios grąžinimo tipas yra vertės nuoroda, arba perdavimas į vertės vertės nuorodos tipo pabaigos pavyzdį] “

Tai reiškia, kad ir lvalue, ir prvalue gali pasibaigti. Šis kodas (nukopijuotas iš viršaus) rodo, kaip „lvalue“, * ptrInt, saugykla (išteklius) vėl naudojama, kai ji ištrinama.

int * ptrInt = naujas int;
* ptrInt = 12;
cout<< *ptrInt <<'\n';
ištrinti ptrInt;
cout<< *ptrInt <<'\n';
* ptrInt = 24;
cout<< *ptrInt <<'\n';

Rezultatas yra:

12
0
24

Ši programa (nukopijuota iš viršaus) parodo, kaip sveiko skaičiaus nuorodos, kuri yra funkcijos grąžinta vertės vertė, saugojimas yra pakartotinai naudojamas pagrindinėje () funkcijoje:

# įtraukti
naudojant vardų sritį std;
int & fn ()

int i = 5;
int & j = i;
grįžti j;

int main ()

int & myInt = fn ();
cout<< myInt <<'\n';
myInt = 17;
cout<< myInt <<'\n';
grąžinti 0;

Rezultatas yra:

5
17

Kai objektas, pvz., I fn () funkcijoje, išeina iš taikymo srities, jis natūraliai sunaikinamas. Šiuo atveju i saugykla vis dar buvo naudojama pagrindinėje () funkcijoje.

Pirmiau pateikti du kodų pavyzdžiai iliustruoja pakartotinį lvalues ​​saugojimo naudojimą. Galima pakartotinai naudoti prvalues ​​(rvalues) saugykloje (žr. Vėliau).

Ši „xvalue“ citata yra iš C ++ specifikacijos:

„Apskritai šios taisyklės poveikis yra tas, kad įvardytos reikšmės nuorodos traktuojamos kaip vertės, o neįvardytos reikšmės nuorodos į objektus - kaip vertės. vertybių nuorodos į funkcijas traktuojamos kaip vertės, nesvarbu, ar jos pavadintos, ar ne.“(Žr. Vėliau).

Taigi, xvalue yra lvalue arba prvalue, kurio išteklius (saugyklą) galima naudoti pakartotinai. xvalues ​​yra lvalues ​​ir prvalues ​​susikirtimo rinkinys.

„Xvalue“ yra daugiau nei tai, kas buvo aptarta šiame straipsnyje. Tačiau „xvalue“ nusipelno viso straipsnio, todėl papildomos „xvalue“ specifikacijos šiame straipsnyje nenagrinėjamos.

Išraiškos kategorijos taksonomijos rinkinys

Kita C ++ specifikacijos citata:

Pastaba: Istoriškai vertybės ir vertės buvo vadinamos todėl, kad jos galėjo pasirodyti kairėje ir dešinėje užduoties pusėje (nors tai apskritai netiesa); glvalues ​​yra „apibendrintos“, „prvalues“ yra „grynos“, o xvalues ​​yra „eXpiring“ vertės. Nepaisant jų pavadinimų, šie terminai klasifikuoja išraiškas, o ne vertybes. - pabaigos užrašas “

Taigi, „Glvalues“ yra lvalues ​​ir xvalues, o rvalues ​​yra xvalues ​​ir prvalues ​​sąjungų rinkinys. xvalues ​​yra lvalues ​​ir prvalues ​​susikirtimo rinkinys.

Nuo šiol frazės kategorijos taksonomija geriau iliustruojama Venno diagrama taip:

Išvada

Vertė yra išraiška, kurios įvertinimas nustato objekto, bitų lauko ar funkcijos tapatumą.

Prvalue yra išraiška, kurios įvertinimas inicijuoja objektą ar bitų lauką arba apskaičiuoja operatoriaus operando vertę, kaip nurodyta kontekste, kuriame ji rodoma.

„Xvalue“ yra „lvalue“ arba „prvalue“, su papildoma nuosavybe, kurią jos išteklius (saugyklą) galima pakartotinai naudoti.

C ++ specifikacija iliustruoja kategorijos taksonomiją medžių diagrama, nurodydama, kad taksonomijoje yra tam tikra hierarchija. Iki šiol taksonomijoje nėra hierarchijos, todėl kai kurie autoriai naudoja Venno diagramą, nes ji taksonomiją parodo geriau nei medžio diagrama.

„Battle for Wesnoth“ pamoka
„Battle for Wesnoth“ yra vienas populiariausių atvirojo kodo strateginių žaidimų, kurį šiuo metu galite žaisti. Šis žaidimas ne tik buvo kuriamas laba...
0 A.D. Pamoka
Iš daugybės strateginių žaidimų 0 A.D. sugeba išsiskirti kaip išsamus pavadinimas ir labai gilus, taktinis žaidimas, nepaisant to, kad yra atviro kodo...
„Unity3D“ pamoka
Įvadas į „Unity 3D“ „Unity 3D“ yra galingas žaidimų kūrimo variklis. Tai yra daugiašalė platforma, kuri leidžia kurti žaidimus mobiliesiems, interneti...