C ++

Taxonómia kategórie výrazov v C ++

Taxonómia kategórie výrazov v C ++

Výpočet je akýkoľvek typ výpočtu, ktorý sa riadi presne stanoveným algoritmom. Výraz je postupnosť operátorov a operandov, ktorá určuje výpočet. Inými slovami, výraz je identifikátor alebo literál alebo postupnosť oboch, ktoré sú spojené operátormi.V programovaní môže mať výraz za následok hodnotu a / alebo spôsobiť, že sa niečo stane. Ak je výsledkom hodnota, výraz je glvalue, rvalue, lvalue, xvalue alebo prvalue. Každá z týchto kategórií je súborom výrazov. Každá množina má definíciu a konkrétne situácie, v ktorých prevláda jej význam, čím sa líši od inej množiny. Každá množina sa nazýva hodnotová kategória.

Poznámka: Hodnota alebo literál sú stále výrazy, takže tieto výrazy klasifikujú výrazy, a nie skutočne hodnoty.

glvalue a rvalue sú dve podmnožiny z výrazu veľkej množiny. glvalue existuje v dvoch ďalších podmnožinách: lvalue a xvalue. rvalue, ďalšia podmnožina pre výraz, existuje aj v dvoch ďalších podmnožinách: xvalue a prvalue. Takže xvalue je podmnožinou glvalue aj rvalue: to znamená, že xvalue je priesečník oboch hodnôt a hodnôt. Nasledujúci diagram taxonómie, prevzatý zo špecifikácie C ++, ilustruje vzťah všetkých množín:

prvalue, xvalue a lvalue sú hodnoty primárnej kategórie. glvalue je spojenie hodnôt a hodnôt x, zatiaľ čo hodnoty r sú spojením hodnôt a prvkov.

Aby ste pochopili tento článok, potrebujete základné znalosti v jazyku C ++; potrebujete tiež vedomosti o rozsahu v C++.

Obsah článku

Základy

Aby ste skutočne porozumeli taxonómii kategórie výrazov, musíte si najskôr spomenúť alebo poznať nasledujúce základné vlastnosti: umiestnenie a objekt, úložisko a zdroj, inicializácia, identifikátor a referencia, odkazy lvalue a rvalue, ukazovateľ, voľný obchod a opätovné použitie a zdroj.

Umiestnenie a objekt

Zvážte nasledujúce vyhlásenie:

int ident;

Toto je deklarácia, ktorá identifikuje umiestnenie v pamäti. Umiestnenie je konkrétna sada po sebe idúcich bajtov v pamäti. Umiestnenie môže pozostávať z jedného bajtu, dvoch bajtov, štyroch bajtov, šesťdesiatich štyroch bajtov atď. Umiestnenie celého čísla pre 32bitový stroj je štyri bajty. Lokalitu je tiež možné identifikovať pomocou identifikátora.

Vo vyššie uvedenej deklarácii umiestnenie nemá žiadny obsah. Znamená to, že nemá žiadnu hodnotu, pretože obsah je hodnota. Takže identifikátor identifikuje miesto (malý súvislý priestor). Keď je umiestneniu daný konkrétny obsah, identifikátor potom identifikuje tak umiestnenie, ako aj obsah; to znamená, že identifikátor potom identifikuje tak umiestnenie, ako aj hodnotu.

Zvážte nasledujúce tvrdenia:

int ident1 = 5;
int ident2 = 100;

Každé z týchto vyhlásení je deklaráciou a definíciou. Prvý identifikátor má hodnotu (obsah) 5 a druhý identifikátor má hodnotu 100. V 32bitovom stroji má každé z týchto umiestnení štyri bajty. Prvý identifikátor identifikuje miesto aj hodnotu. Druhý identifikátor tiež identifikuje obidve.

Objekt je pomenovaná oblasť úložiska v pamäti. Takže objekt je buď umiestnenie bez hodnoty, alebo umiestnenie s hodnotou.

Ukladanie a zdroje objektov

Umiestnenie objektu sa tiež nazýva úložisko alebo prostriedok objektu.

Inicializácia

Zvážte nasledujúci segment kódu:

int ident;
ident = 8;

Prvý riadok deklaruje identifikátor. Táto deklarácia poskytuje umiestnenie (úložisko alebo zdroj) celého objektu, ktorý ho identifikuje menom, ident. Nasledujúci riadok vloží hodnotu 8 (v bitoch) na miesto identifikované ident. Uvedenie tejto hodnoty je inicializácia.

Nasledujúce tvrdenie definuje vektor s obsahom 1, 2, 3, 4, 5 identifikovaný pomocou vtr:

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

Tu sa inicializácia pomocou 1, 2, 3, 4, 5 vykonáva v rovnakom výroku definície (deklarácia). Operátor priradenia sa nepoužíva. Nasledujúci príkaz definuje pole s obsahom 1, 2, 3, 4, 5:

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

Tentokrát sa na inicializáciu použil operátor priradenia.

Identifikátor a referencia

Zvážte nasledujúci segment kódu:

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

Výstup je:

4 4 4

ident je identifikátor, zatiaľ čo ref1 a ref2 sú referencie; odkazujú na to isté miesto. Odkaz je synonymom identifikátora. Zvyčajne sú ref1 a ref2 rôzne názvy jedného objektu, zatiaľ čo ident je identifikátor toho istého objektu. Ident sa však dá stále nazvať názvom objektu, čo znamená, ident, ref1 a ref2 pomenujú to isté miesto.

Hlavný rozdiel medzi identifikátorom a odkazom je v tom, že keď sa odovzdá ako argument funkcii, ak sa odovzdá identifikátorom, vytvorí sa kópia identifikátora vo funkcii, zatiaľ čo ak sa odovzdá odkazom, použije sa rovnaké umiestnenie v rámci funkcie. Takže prechádzanie okolo identifikátora končí na dvoch miestach, zatiaľ čo prechádzanie okolo odkazu končí na rovnakom jednom mieste.

referencia lvalue a referencia rvalue

Bežný spôsob vytvorenia referencie je nasledovný:

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

Úložisko (zdroj) je umiestnené a identifikované najskôr (s názvom ako ident) a potom je urobený odkaz (s názvom ako ref). Pri prechode ako argumentu k funkcii sa vo funkcii vytvorí kópia identifikátora, zatiaľ čo v prípade odkazu sa vo funkcii použije (označuje sa) pôvodné umiestnenie.

Dnes je možné mať iba referenciu bez jej identifikácie. To znamená, že je možné najskôr vytvoriť referenciu bez identifikátora miesta. Používa sa &&, ako je uvedené v nasledujúcom vyhlásení:

int && ref = 4;

Tu neexistuje žiadna predchádzajúca identifikácia. Ak chcete získať prístup k hodnote objektu, jednoducho použite ref, ako by ste použili vyššie uvedený ident.

S deklaráciou && nie je možné odovzdať argument funkcii pomocou identifikátora. Jedinou voľbou je prejsť referenciou. V takom prípade je vo funkcii použité iba jedno umiestnenie a nie druhé skopírované miesto ako s identifikátorom.

Referenčné vyhlásenie s & sa nazýva lvalue reference. Referenčné vyhlásenie s && sa nazýva rvalue reference, čo je tiež referenčná hodnota (pozri nižšie).

Ukazovateľ

Zvážte nasledujúci kód:

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

Výstup je 5.

Tu je ptdInt identifikátor, ako je identifikácia vyššie. Namiesto jedného sú tu dva objekty (umiestnenia): zahrotený objekt, ptdInt identifikovaný pomocou ptdInt a ukazovateľový objekt, ptrInt identifikovaný pomocou ptrInt. & ptdInt vráti adresu poukázaného objektu a vloží ju ako hodnotu do ukazovateľa ptrInt objektu. Na vrátenie (získanie) hodnoty zahroteného objektu použite identifikátor ukazovateľa ako v „* ptrInt“.

Poznámka: ptdInt je identifikátor a nie referencia, zatiaľ čo meno ref, ktoré sme už spomenuli, je referenciou.

Druhý a tretí riadok vo vyššie uvedenom kóde je možné zmenšiť na jeden riadok, čo vedie k nasledujúcemu kódu:

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

Poznámka: Keď sa ukazovateľ zvyšuje, smeruje na ďalšie miesto, ktoré nie je súčtom hodnoty 1. Keď sa ukazovateľ zníži, smeruje na predchádzajúce miesto, čo nie je odčítaním hodnoty 1.

Obchod zadarmo

Operačný systém vyhradzuje pamäť pre každý spustený program. Pamäť, ktorá nie je alokovaná k žiadnemu programu, sa nazýva voľný obchod. Výraz, ktorý vráti umiestnenie celého čísla z bezplatného obchodu, je:

nová int

Týmto sa vráti umiestnenie pre celé číslo, ktoré nie je identifikované. Nasledujúci kód ilustruje, ako používať ukazovateľ v obchode zdarma:

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

Výstup je 12.

Na zničenie objektu použite nasledujúci výraz:

vymazať ptrInt;

Argumentom výrazu delete je ukazovateľ. Nasledujúci kód ilustruje jeho použitie:

int * ptrInt = new int;
* ptrInt = 12;
vymazať ptrInt;
cout<< *ptrInt <<'\n';

Výstup je 0, a nič podobné ako nulové alebo nedefinované. vymazať nahradí hodnotu miesta predvolenou hodnotou konkrétneho typu umiestnenia, potom umožní umiestnenie znova použiť. Predvolená hodnota pre int umiestnenie je 0.

Opätovné použitie zdroja

V taxonómii kategórie výrazov je opätovné použitie zdroja rovnaké ako opätovné použitie umiestnenia alebo úložiska pre objekt. Nasledujúci kód ilustruje, ako možno znova použiť miesto z bezplatného obchodu:

int * ptrInt = new int;
* ptrInt = 12;
cout<< *ptrInt <<'\n';
vymazať ptrInt;
cout<< *ptrInt <<'\n';
* ptrInt = 24;
cout<< *ptrInt <<'\n';

Výstup je:

12
0
24

Neidentifikovanému miestu sa najskôr priradí hodnota 12. Potom sa vymaže obsah miesta (teoreticky sa vymaže objekt). Hodnota 24 je znovu priradená k rovnakému miestu.

Nasledujúci program ukazuje, ako sa opätovne používa celočíselný odkaz vrátený funkciou:

#include
pomocou namespace std;
int & fn ()

int i = 5;
int & j = i;
návrat j;

int main ()

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

Výstup je:

5
17

Objekt ako i, deklarovaný v miestnom rozsahu (rozsah funkcie), prestane existovať na konci miestneho rozsahu. Funkcia fn () vyššie však vráti referenciu i. Prostredníctvom tohto vráteného odkazu názov, myInt vo funkcii main (), znova použije miesto identifikované i pre hodnotu 17.

lhodnota

Hodnota lvalue je výraz, ktorého vyhodnotenie určuje identitu objektu, bitového poľa alebo funkcie. Identita je oficiálna identita, ako je ident vyššie, alebo referenčný názov lvalue, ukazovateľ alebo názov funkcie. Zvážte nasledujúci funkčný kód:

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

++ptr; --ptr;
vrátiť myInt;

MyInt je tu hodnota; myRef je referenčný výraz lvalue; * ptr je výraz lvalue, pretože jeho výsledok je identifikovateľný s ptr; ++ ptr alebo -ptr je výraz lvalue, pretože jeho výsledok je identifikovateľný s novým stavom (adresou) ptr a fn je lvalue (výraz).

Zvážte nasledujúci segment kódu:

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

V druhom výroku má umiestnenie pre „a“ 2 a je identifikovateľné pomocou „a“, a teda aj lvalue. Miesto pre b má 8 a je identifikovateľné podľa b, a teda aj s hodnotou l. Miesto pre c bude mať súčet a je identifikovateľné pomocou c, a teda aj lvalue. V druhom výroku sú výrazy alebo hodnoty 16 a 64 rvalue (pozri nižšie).

Zvážte nasledujúci segment kódu:

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

Výstup je „v";

seq je pole. Miesto pre „v“ alebo akákoľvek podobná hodnota v poli je označená seq [i], kde i je index. Takže výraz, seq [i], je výraz lvalue. seq, ktorý je identifikátorom celého poľa, je tiež hodnotou l.

prvalue

Prvou hodnotou je výraz, ktorého vyhodnotenie inicializuje objekt alebo bitové pole alebo počíta hodnotu operandu operátora, ako je určené v kontexte, v ktorom sa nachádza.

Vo vyhlásení,

int myInt = 256;

256 je prvá hodnota (výraz prvej hodnoty), ktorá inicializuje objekt identifikovaný myInt. Na tento objekt sa neodkazuje.

Vo vyhlásení,

int && ref = 4;

4 je prvá hodnota (výraz prvej hodnoty), ktorá inicializuje objekt odkazovaný ref. Tento objekt nie je oficiálne identifikovaný. ref je príklad referenčného výrazu rvalue alebo referenčného výrazu prvalue; je to meno, ale nie oficiálny identifikátor.

Zvážte nasledujúci segment kódu:

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

6 je prvočíslo, ktoré inicializuje objekt identifikovaný pomocou ident; na objekt odkazuje aj ref. Tu je ref referenciou lvalue a nie referenciou prvej hodnoty.

Zvážte nasledujúci segment kódu:

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

15 a 63 sú každá konštanta, ktorá sa počíta pre seba, a vytvára operand (v bitoch) pre operátor sčítania. Takže 15 alebo 63 je prvoradý výraz.

Akýkoľvek literál, okrem reťazcového literálu, je prvalue (t.j.e., výraz prvej hodnoty). Takže literál ako 58 alebo 58.53, alebo pravda alebo lož, je prvočíslo. Literál sa dá použiť na inicializáciu objektu alebo by sa sám pre seba (do inej formy v bitoch) vypočítal ako hodnota operandu pre operátora. Vo vyššie uvedenom kóde inicializuje literál 2 objekt, a. Tiež sa počíta ako operand pre operátora priradenia.

Prečo nie je reťazcový literál prvočíslo? Zvážte nasledujúci kód:

char str [] = "láska, nenávisť";
cout << str <<'\n';
cout << str[5] <<'\n';

Výstup je:

láska nie nenávisť
n

str identifikuje celý reťazec. Takže výraz str a nie to, čo identifikuje, je hodnota. Každý znak v reťazci je možné identifikovať podľa reťazca str [i], kde i je index. Výraz str [5], a nie znak, ktorý identifikuje, má hodnotu. Reťazcový literál je lvalue a nie prvalue.

V nasledujúcom vyhlásení inicializuje pole literál objekt, arr:

ptrInt ++ alebo ptrInt-- 

Tu je ptrInt ukazovateľ na celé číslo. Celý výraz, a nie konečná hodnota umiestnenia, na ktoré ukazuje, je prvalue (výraz). Je to preto, lebo výraz ptrInt ++ alebo ptrInt- identifikuje pôvodnú prvú hodnotu svojho umiestnenia a nie druhú konečnú hodnotu toho istého umiestnenia. Na druhej strane -ptrInt alebo -ptrInt je hodnota, pretože identifikuje jedinú hodnotu podielu na danom mieste. Ďalším spôsobom, ako sa na to pozerať, je, že pôvodná hodnota počíta druhú konečnú hodnotu.

V druhom výroku nasledujúceho kódu možno a alebo b stále považovať za prvočíslo:

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

Takže a alebo b v druhom výroku je lvalue, pretože identifikuje objekt. Je tiež prvou hodnotou, pretože počíta pre celé číslo operandu operátora sčítania.

(new int), a nie umiestnenie, ktoré vytvorí, je prvalue. V nasledujúcom vyhlásení je spiatočná adresa umiestnenia priradená k objektu ukazovateľa:

int * ptrInt = nový int

Tu je * ptrInt hodnota, zatiaľ čo (new int) je hodnota. Pamätajte, že lvalue alebo prvalue je výraz. (new int) neidentifikuje žiadny objekt. Vrátenie adresy neznamená identifikáciu objektu menom (napríklad ident, hore). V * ptrInt je názov, ptrInt, to, čo skutočne identifikuje objekt, takže * ptrInt je hodnota. Na druhej strane je (new int) prvou hodnotou, pretože počíta nové umiestnenie na adresu hodnoty operandu pre operátor priradenia =.

xvalue

Dnes lvalue znamená Location Value; prvalue znamená „čistá“ rvalue (nižšie sa dozviete, čo znamená rvalue). Dnes xvalue znamená „eXpiring“ lvalue.

Definícia hodnoty xvalue, uvedená v špecifikácii C ++, je nasledovná:

„Xvalue je glvalue, ktorá označuje objekt alebo bitové pole, ktorého zdroje je možné znovu použiť (zvyčajne preto, že je takmer na konci svojej životnosti). [Príklad: Niektoré druhy výrazov, ktoré zahŕňajú odkazy na rvalue, vedú k xvalue, ako napríklad volanie funkcie, ktorej návratovým typom je odkaz rvalue alebo cast na typ odkazu rvalue - koncový príklad] “

To znamená, že platnosť lvalue aj prvalue môže vypršať. Nasledujúci kód (skopírovaný zhora) ukazuje, ako sa úložisko (zdroj) hodnoty l *, ptrInt po odstránení znova použije.

int * ptrInt = new int;
* ptrInt = 12;
cout<< *ptrInt <<'\n';
vymazať ptrInt;
cout<< *ptrInt <<'\n';
* ptrInt = 24;
cout<< *ptrInt <<'\n';

Výstup je:

12
0
24

Nasledujúci program (skopírovaný z vyššie uvedeného) ukazuje, ako sa úložisko celočíselného odkazu, ktorým je odkaz lvalue vrátený funkciou, znovu používa vo funkcii main ():

#include
pomocou namespace std;
int & fn ()

int i = 5;
int & j = i;
návrat j;

int main ()

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

Výstup je:

5
17

Keď objekt ako i vo funkcii fn () vyjde z rozsahu, prirodzene sa zničí. V tomto prípade bolo úložisko i stále znovu použité vo funkcii main ().

Vyššie uvedené dva ukážky kódu ilustrujú opätovné použitie ukladania hodnôt. Je možné, aby úložisko bolo opätovne použité prvalues ​​(rvalues) (pozri ďalej).

Nasledujúca citácia týkajúca sa hodnoty xvalue je zo špecifikácie C ++:

„Vo všeobecnosti platí toto pravidlo tak, že s pomenovanými odkazmi na rvalue sa zaobchádza ako na lvalu a nepomenované odkazy na rvalue na objekty sa považujú za xvalue. s hodnotami rvalue na funkcie sa zaobchádza ako s hodnotami l bez ohľadu na to, či sú pomenované alebo nie.”(Pozri neskôr).

Takže xvalue je lvalue alebo prvalue, ktorých zdroje (úložisko) je možné znovu použiť. xvalues ​​je priesečník množiny lvalue a prvalues.

Hodnota xvalue predstavuje viac, ako to, čo bolo predmetom tohto článku. Xvalue si však zaslúži celý článok sám o sebe, a preto sa v tomto článku nezaoberáme ďalšími špecifikáciami xvalue.

Sada taxonómie kategórií výrazov

Ďalšia citácia zo špecifikácie C ++:

Poznámka: Historicky sa hodnoty a hodnoty hodnotili takzvaným spôsobom, pretože sa mohli objaviť na ľavej a pravej strane úlohy (aj keď to už všeobecne neplatí); glvalue sú „zovšeobecnené“ lvalue, prvalues ​​sú „čisté“ rvalue a xvalues ​​sú „eXpiring“ lvalue. Napriek svojim menám tieto výrazy klasifikujú výrazy, nie hodnoty. - záverečná poznámka “

Glvalues ​​je zjednocujúca množina lhodnot a xhodnot a rvalue sú zjednocujúca množina xhodnot a prv. xvalues ​​je priesečník množiny lvalue a prvalues.

Odteraz je taxonómia kategórie výrazov lepšie ilustrovaná Vennovým diagramom nasledujúcim spôsobom:

Záver

Hodnota lvalue je výraz, ktorého vyhodnotenie určuje identitu objektu, bitového poľa alebo funkcie.

Prvou hodnotou je výraz, ktorého vyhodnotenie inicializuje objekt alebo bitové pole alebo počíta hodnotu operandu operátora, ako je určené v kontexte, v ktorom sa vyskytuje.

Xvalue je lvalue alebo prvalue, s ďalšou vlastnosťou, že jeho zdroje (úložisko) môžu byť znovu použité.

Špecifikácia C ++ ilustruje taxonómiu kategórie výrazov so stromovým diagramom, čo naznačuje, že v taxonómii existuje určitá hierarchia. Odteraz v taxonómii nie je žiadna hierarchia, takže niektorí autori používajú Vennov diagram, pretože ten lepšie ilustruje taxonómiu ako stromový diagram.

Hry Najlepšie hry Oculus App Lab
Najlepšie hry Oculus App Lab
Ak ste vlastníkom náhlavnej súpravy Oculus, musíte byť informovaní o bočnom nakladaní. Sideloading je proces inštalácie neuloženého obsahu do náhlavne...
Hry Top 10 hier, ktoré sa dajú hrať na Ubuntu
Top 10 hier, ktoré sa dajú hrať na Ubuntu
Platforma Windows je jednou z dominujúcich platforiem pre hry kvôli obrovskému percentu hier, ktoré sa dnes vyvíjajú na natívnu podporu systému Window...
Hry 5 najlepších arkádových hier pre Linux
5 najlepších arkádových hier pre Linux
V dnešnej dobe sú počítače vážne stroje používané na hranie hier. Ak nemôžete dosiahnuť nové najvyššie skóre, budete vedieť, čo tým myslím. V tomto pr...