C ++

Ilmaisuluokan taksonomia C ++ ssa

Ilmaisuluokan taksonomia C ++ ssa

Laskenta on mitä tahansa laskutyyppiä, joka noudattaa hyvin määriteltyä algoritmia. Lauseke on operaattoreiden ja operandien sarja, joka määrittää laskennan. Toisin sanoen lauseke on tunniste tai literaali tai molempien sarja, johon operaattorit ovat liittyneet.Ohjelmoinnissa lauseke voi johtaa arvoon ja / tai aiheuttaa jonkin tapahtuman. Kun se johtaa arvoon, lauseke on glvalue, rvalue, lvalue, xvalue tai prvalue. Jokainen näistä luokista on joukko lausekkeita. Jokaisella joukolla on määritelmä ja erityistilanteet, joissa sen merkitys vallitsee, erottaen sen toisesta joukosta. Kutakin joukkoa kutsutaan arvoluokaksi.

Merkintä: Arvo tai kirjaimellinen on edelleen lauseke, joten nämä termit luokittelevat lausekkeita eivätkä oikeastaan ​​arvoja.

glvalue ja rvalue ovat kaksi joukkoa ison joukon lausekkeesta. glvalue on olemassa kahdessa muussa osajoukossa: lvalue ja xvalue. rvalue, toinen lausekkeen osajoukko, esiintyy myös kahdessa muussa osajoukossa: xvalue ja prvalue. Joten, xvalue on sekä glvalue- että rvalue-osajoukko: ts. Xvalue on sekä glvalue- että rvalue-leikkauspiste. Seuraava taksonomiakaavio, joka on otettu C ++ -määrityksestä, kuvaa kaikkien joukkojen suhdetta:

prvalue, xvalue ja lvalue ovat ensisijaisia ​​luokan arvoja. glvalue on arvojen ja xvalues, kun taas rvalues ​​on xvalues ​​ja prvalues ​​yhdistys.

Tarvitset perustiedot C ++: sta ymmärtääksesi tämän artikkelin; tarvitset myös tietoa laajuudesta C: ssä++.

Artikkelin sisältö

Perusasiat

Jotta voisit todella ymmärtää lausekeluokituksen taksonomian, sinun on ensin muistettava tai tunnettava seuraavat perusominaisuudet: sijainti ja esine, tallennustila ja resurssi, alustaminen, tunniste ja viite, arvon ja arvon arvot, osoitin, ilmainen kauppa ja resurssi.

Sijainti ja kohde

Harkitse seuraavaa julistusta:

int ident;

Tämä on ilmoitus, joka tunnistaa sijainnin muistissa. Sijainti on tietty sarja peräkkäisiä tavuja muistissa. Sijainti voi koostua yhdestä tavusta, kahdesta tavusta, neljä tavusta, kuusikymmentäneljä tavua jne. 32-bittisen koneen kokonaisluvun sijainti on neljä tavua. Myös sijainti voidaan tunnistaa tunnisteella.

Yllä olevassa ilmoituksessa sijainnilla ei ole sisältöä. Se tarkoittaa, että sillä ei ole arvoa, koska sisältö on arvo. Joten tunniste tunnistaa sijainnin (pieni jatkuva tila). Kun sijainnille annetaan tietty sisältö, tunniste tunnistaa sitten sekä sijainnin että sisällön; eli tunniste identifioi sitten sekä sijainnin että arvon.

Harkitse seuraavia väitteitä:

int identi = 5;
int ident2 = 100;

Jokainen näistä lausumista on julistus ja määritelmä. Ensimmäisen tunnisteen arvo (sisältö) on 5 ja toisen tunnisteen arvo 100. 32-bittisessä koneessa kukin näistä paikoista on neljä tavua pitkä. Ensimmäinen tunniste tunnistaa sekä sijainnin että arvon. Toinen tunniste tunnistaa myös molemmat.

Objekti on nimetty muistialue. Joten esine on joko sijainti ilman arvoa tai sijainti, jolla on arvo.

Kohteen tallennus ja resurssi

Objektin sijaintia kutsutaan myös objektin tallennustilaksi tai resurssiksi.

Alustus

Harkitse seuraavaa koodisegmenttiä:

int ident;
ident = 8;

Ensimmäinen rivi ilmoittaa tunnisteen. Tämä ilmoitus antaa sijainnin (tallennustilan tai resurssin) kokonaislukuobjektille, tunnistamalla sen nimellä, ident. Seuraava rivi lisää arvon 8 (bitteinä) identifikaation tunnistamaan sijaintiin. Tämän arvon asettaminen on alustaminen.

Seuraava lause määrittelee vektorin, jonka sisältö on 1, 2, 3, 4, 5 ja jonka tunnistaa vtr:

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

Tässä alustaminen tunnuksilla 1, 2, 3, 4, 5 suoritetaan samassa määritelmän (ilmoituksen) lauseessa. Määritysoperaattoria ei käytetä. Seuraava lause määrittelee taulukon, jonka sisältö on 1, 2, 3, 4, 5:

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

Tällä kertaa alustuksessa on käytetty määritysoperaattoria.

Tunniste ja viite

Harkitse seuraavaa koodisegmenttiä:

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

Tuotos on:

4 4 4

ident on tunniste, kun taas ref1 ja ref2 ovat viitteitä; ne viittaavat samaan sijaintiin. Viite on tunnisteen synonyymi. Perinteisesti ref1 ja ref2 ovat yhden objektin eri nimiä, kun taas ident on saman objektin tunniste. Identia voidaan silti kutsua objektin nimeksi, mikä tarkoittaa ident, ref1 ja ref2 nimeä samalle sijainnille.

Tärkein ero tunnuksen ja viitteen välillä on se, että kun se välitetään argumentiksi funktiolle, jos se välitetään tunnisteella, kopio tehdään toiminnon tunnisteelle, kun taas jos se välitetään viitteenä, samaa sijaintia käytetään toiminto. Joten tunnisteen ohittaminen johtaa kahteen sijaintiin, kun taas viittaus ohittaa saman sijainnin.

lvalue Reference ja rvalue Reference

Normaali tapa luoda viite on seuraava:

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

Tallennustila (resurssi) paikannetaan ja tunnistetaan ensin (esimerkiksi nimellä), ja sitten tehdään viite (nimellä kuten viite). Kun välitetään argumenttina funktiolle, kopio tunnisteesta tehdään funktiossa, kun taas viitteen tapauksessa funktiossa käytetään (viitataan) alkuperäistä sijaintia.

Nykyään on mahdollista saada vain viite tunnistamatta sitä. Tämä tarkoittaa, että ensin on mahdollista luoda viite ilman, että sijainnille on tunnus. Tässä käytetään &&, kuten seuraava lausunto osoittaa:

int && ref = 4;

Täällä ei ole edeltävää tunnistetta. Voit käyttää objektin arvoa yksinkertaisesti käyttämällä viittausta kuten käyttäisit yllä olevaa tunnusta.

&& -ilmoituksen avulla ei ole mahdollista välittää argumenttia funktiolle tunnisteella. Ainoa valinta on ohittaa viite. Tässä tapauksessa toiminnossa käytetään vain yhtä sijaintia eikä toista kopioitua sijaintia kuten tunnisteessa.

Viitearvot, joissa on &, kutsutaan arvon arvoksi. Viiteilmoitusta, jossa on &&, kutsutaan rvalue-viitteeksi, joka on myös prvalue-viite (katso alla).

Osoitin

Harkitse seuraavaa koodia:

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

Tulos on 5.

Tässä ptdInt on tunniste, kuten edellä oleva tunnus. Tässä on kaksi kohdetta (sijaintia) yhden sijasta: terävä esine, ptdInt: n tunnistama ptdInt ja ptrInt: n tunnistama osoitinobjekti ptrInt. & ptdInt palauttaa teräväkohteen osoitteen ja asettaa sen arvoksi osoitin ptrInt -objektiin. Jos haluat palauttaa (saada) teräväkohteen arvon, käytä osoitinobjektin tunnusta, kuten kohdassa "* ptrInt".

Merkintä: ptdInt on tunniste eikä viite, kun taas aiemmin mainittu nimi, ref, on viite.

Edellä olevan koodin toinen ja kolmas rivi voidaan supistaa yhdeksi riviksi, mikä johtaa seuraavaan koodiin:

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

Merkintä: Kun osoitinta kasvatetaan, se osoittaa seuraavaan sijaintiin, joka ei ole arvon 1 lisäys. Kun osoitinta vähennetään, se osoittaa edelliseen sijaintiin, joka ei ole arvon 1 vähennys.

Ilmainen kauppa

Käyttöjärjestelmä varaa muistin jokaiselle käynnissä olevalle ohjelmalle. Muistia, jota ei ole varattu mihinkään ohjelmaan, kutsutaan ilmaiseksi kaupaksi. Ilmaus, joka palauttaa kokonaisluvun sijainnin ilmaisesta kaupasta, on:

uusi int

Tämä palauttaa sijainnin kokonaisluvulle, jota ei tunnisteta. Seuraava koodi kuvaa, kuinka osoitinta käytetään ilmaisen myymälän kanssa:

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

Tulos on 12.

Tuhoa objekti käyttämällä poista-lauseketta seuraavasti:

poista ptrInt;

Lausekkeen poisto-argumentti on osoitin. Seuraava koodi kuvaa sen käyttöä:

int * ptrInt = uusi int;
* ptrInt = 12;
poista ptrInt;
cout<< *ptrInt <<'\n';

Tulos on 0, eikä mitään sellaista kuin tyhjä tai määrittelemätön. delete korvaa sijainnin arvon tietyn sijaintityypin oletusarvolla ja sallii sitten sijainnin uudelleenkäytön. Int-sijainnin oletusarvo on 0.

Resurssin uudelleenkäyttö

Ilmaisuluokan taksonomiassa resurssin uudelleenkäyttö on sama kuin sijainnin tai objektin uudelleenkäyttö. Seuraava koodi havainnollistaa, kuinka sijaintia vapaasta kaupasta voidaan käyttää uudelleen:

int * ptrInt = uusi int;
* ptrInt = 12;
cout<< *ptrInt <<'\n';
poista ptrInt;
cout<< *ptrInt <<'\n';
* ptrInt = 24;
cout<< *ptrInt <<'\n';

Tuotos on:

12
0
24

Arvo 12 määritetään ensin tunnistamattomalle sijainnille. Sitten sijainnin sisältö poistetaan (teoriassa objekti poistetaan). Arvo 24 määritetään uudelleen samaan sijaintiin.

Seuraava ohjelma näyttää, kuinka funktion palauttama kokonaislukuviite käytetään uudelleen:

#sisältää
käyttämällä nimitilaa vakio;
int & fn ()

int i = 5;
int & j = i;
paluu j;

int main ()

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

Tuotos on:

5
17

Kohde, kuten i, ilmoitettu paikallisessa laajuudessa (toiminnon laajuus), lakkaa olemasta paikallisen laajuuden lopussa. Yllä oleva funktio fn () palauttaa kuitenkin i: n viitteen. Tämän palautetun viitteen avulla nimi, myInt main () -funktiossa, käyttää uudelleen i: n tunnistamaa sijaintia arvoon 17.

arvo

Lvalue on lauseke, jonka arviointi määrittää objektin, bittikentän tai funktion identiteetin. Identiteetti on virallinen identiteetti, kuten yllä oleva identiteetti, tai arvoarvoinen viitenimi, osoitin tai toiminnon nimi. Harkitse seuraavaa toimivaa koodia:

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

++ptr; --ptr;
palauta myInt;

Tässä myInt on arvo; myRef on arvoarvoinen lauseke; * ptr on arvoarvo, koska sen tulos on tunnistettavissa ptr: n kanssa; ++ ptr tai -ptr on lvalue-lauseke, koska sen tulos voidaan tunnistaa ptr: n uudesta tilasta (osoite) ja fn on lvalue (lauseke).

Harkitse seuraavaa koodisegmenttiä:

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

Toisessa lauseessa a: n sijainnilla on 2 ja se voidaan tunnistaa a: lla, ja niin on myös arvo. B: n sijainnissa on 8 ja se on tunnistettavissa b: llä, ja niin on myös arvo. C: n sijainnilla on summa, ja se on tunnistettavissa c: llä, ja niin on myös arvo. Toisessa lauseessa lausekkeet tai arvot 16 ja 64 ovat arvoja (katso alla).

Harkitse seuraavaa koodisegmenttiä:

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

Tuotos on 'v";

seq on taulukko. V: n tai minkä tahansa vastaavan arvon matriisissa sijainti tunnistetaan sekvenssillä [i], missä i on indeksi. Joten lauseke seq [i] on arvoarvo. seq, joka on koko matriisin tunniste, on myös arvo.

arvo

Prvalue on lauseke, jonka arviointi alustaa objektin tai bittikentän tai laskee operaattorin operandin arvon kontekstin määrittelemällä tavalla, jossa se esiintyy.

Lausunnossa,

int myInt = 256;

256 on prvalue (prvalue-lauseke), joka alustaa myInt: n tunnistaman objektin. Tähän objektiin ei viitata.

Lausunnossa,

int && ref = 4;

4 on prvalue (prvalue-lauseke), joka alustaa objektin, johon viite viittaa. Tätä objektia ei tunnisteta virallisesti. viite on esimerkki rvalue-vertailulausekkeesta tai prvalue-vertailulausekkeesta; se on nimi, mutta ei virallinen tunniste.

Harkitse seuraavaa koodisegmenttiä:

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

6 on prvalue, joka alustaa identifioidun objektin; esineeseen viittaa myös viite. Tässä viite on arvoarvo eikä viitearvo.

Harkitse seuraavaa koodisegmenttiä:

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

Kuviot 15 ja 63 ovat kumpikin vakio, joka laskee itselleen ja tuottaa operandin (bitteinä) lisäysoperaattorille. Joten 15 tai 63 on prvalue-lauseke.

Mikä tahansa kirjaimellinen, paitsi merkkijono literaali, on prvalue (i.e., prvalue-lauseke). Joten kirjaimellinen kuten 58 tai 58.53, tai tosi tai väärä, on prvalue. Literaalia voidaan käyttää objektin alustamiseen tai se laskisi itselleen (jossakin muussa muodossa bitteinä) operandin arvoksi operaattorille. Edellä olevassa koodissa kirjaimellinen 2 alustaa objektin, a. Se laskee itsensä myös operaattorin operandiksi.

Miksi merkkijono kirjaimellinen ei ole arvoarvo? Harkitse seuraavaa koodia:

char str [] = "rakkaus, ei viha";
cout << str <<'\n';
cout << str[5] <<'\n';

Tuotos on:

rakkautta ei vihaa
n

str identifioi koko merkkijonon. Joten lauseke, str, eikä se, mitä se tunnistaa, on arvo. Kukin merkkijono voidaan tunnistaa merkillä str [i], missä i on hakemisto. Lauseke str [5], eikä sen tunnistama merkki, on arvo. Merkkijonon kirjain on arvo eikä arvo.

Seuraavassa lausekkeessa matriisi kirjaimellisesti alustaa objektin arr:

ptrInt ++ tai ptrInt-- 

Tässä ptrInt on osoitin kokonaislukupaikalle. Koko lauseke, eikä sen osoittaman sijainnin lopullinen arvo, on prvalue (lauseke). Tämä johtuu siitä, että lauseke ptrInt ++ tai ptrInt-, identifioi sijainnin alkuperäisen ensimmäisen arvon eikä saman sijainnin toisen lopullisen arvon. Toisaalta -ptrInt tai -ptrInt on arvo, koska se tunnistaa paikan ainoan kiinnostuksen arvon. Toinen tapa tarkastella sitä on, että alkuperäinen arvo laskee toisen lopullisen arvon.

Seuraavan koodin toisessa lausekkeessa a tai b voidaan silti pitää arvona:

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

Joten toisen lauseen a tai b on arvo, koska se tunnistaa objektin. Se on myös arvo, koska se lasketaan summausoperaattorin operandin kokonaisluvuksi.

(uusi int), eikä sija, jonka se määrittää, on esiarvo. Seuraavassa lausekkeessa sijainnin paluuosoite on osoitettu osoitinobjektille:

int * ptrInt = uusi int

Tässä * ptrInt on arvo, kun taas (uusi int) on arvo. Muista, että lvalue tai prvalue on lauseke. (uusi int) ei tunnista mitään objektia. Osoitteen palauttaminen ei tarkoita kohteen tunnistamista nimellä (kuten yllä oleva tunnus). Kohdassa * ptrInt nimi ptrInt tunnistaa objektin, joten * ptrInt on arvo. Toisaalta (uusi int) on prvalue, koska se laskee uuden sijainnin osoitteen operaattoriarvon osoitteeksi =.

xvalue

Nykyään lvalue tarkoittaa sijainnin arvoa; prvalue tarkoittaa puhdas rvalue (katso mitä rvalue tarkoittaa alla). Nykyään xvalue tarkoittaa eXpiring-arvoa.

Xvalue-määritelmä, joka on lainattu C ++ -määrityksestä, on seuraava:

"Xvalue on glvalue, joka tarkoittaa objektia tai bittikenttää, jonka resursseja voidaan käyttää uudelleen (yleensä koska se on lähellä elinkaarensa loppua). [Esimerkki: Tietyntyyppiset lausekkeet, jotka sisältävät rvalue-viitteitä, tuottavat x-arvoja, kuten kutsu funktiolle, jonka palautustyyppi on rvalue-viite, tai cast to rvalue -viitetyypin loppuesimerkki] "

Tämä tarkoittaa, että sekä arvo että arvon voi vanhentua. Seuraava koodi (kopioitu ylhäältä) osoittaa, kuinka lvalue, * ptrInt: n tallennustilaa (resurssia) käytetään uudelleen sen poistamisen jälkeen.

int * ptrInt = uusi int;
* ptrInt = 12;
cout<< *ptrInt <<'\n';
poista ptrInt;
cout<< *ptrInt <<'\n';
* ptrInt = 24;
cout<< *ptrInt <<'\n';

Tuotos on:

12
0
24

Seuraava ohjelma (kopioitu ylhäältä) osoittaa, kuinka kokonaisluvuviitteen, joka on funktion palauttama arvoarvo, viittausta käytetään uudelleen pääfunktiossa ():

#sisältää
käyttämällä nimitilaa vakio;
int & fn ()

int i = 5;
int & j = i;
paluu j;

int main ()

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

Tuotos on:

5
17

Kun objekti, kuten i fn () -funktiossa, menee ulkopuolelle, se luonnollisesti tuhoutuu. Tässä tapauksessa i: n tallennustilaa on edelleen käytetty pää () -funktiossa.

Edellä olevat kaksi koodinäytettä kuvaavat arvojen varastoinnin uudelleenkäyttöä. Prvalues ​​(rvalues) on mahdollista käyttää uudelleen varastoinnissa (katso myöhemmin).

Seuraava xvaluea koskeva lainaus on C ++ -määrityksestä:

"Yleensä tämän säännön vaikutus on, että nimettyjä arvoviittauksia käsitellään arvoina ja nimettömiä viittauksia kohteisiin pidetään x-arvoina. rvalue-viittaukset funktioihin käsitellään arvoina riippumatta siitä, onko ne nimetty vai ei." (nähdä myöhemmin).

Joten, xvalue on lvalue tai prvalue, jonka resursseja (tallennustilaa) voidaan käyttää uudelleen. xvalues ​​on lvalues- ja prvalues-leikkausjoukko.

Xvalue-arvoa on enemmän kuin mitä tässä artikkelissa on käsitelty. Xvalue ansaitsee kuitenkin kokonaisen artikkelin yksin, joten xvaluen lisäominaisuuksia ei käsitellä tässä artikkelissa.

Ilmaisuluokan taksonomiasarja

Toinen lainaus C ++ -määrityksestä:

"Merkintä: Historiallisesti arvot ja arvot olivat niin sanottuja, koska ne saattoivat näkyä tehtävän vasemmalla ja oikealla puolella (vaikka tämä ei yleensä ole enää totta); glvalues ​​ovat "yleistettyjä" arvoja, prvalues ​​ovat "puhtaita" arvoja ja xvalues ​​ovat "eXpiring" -arvoja. Nimistä huolimatta nämä termit luokittelevat ilmaisuja, ei arvoja. - loppuviesti ”

Joten, glvalues ​​on unioniarvo arvoja ja xvalues ​​ja rvalues ​​ovat unionijoukko xvalues ​​ja prvalues. xvalues ​​on lvalues- ja prvalues-leikkausjoukko.

Tästä lähtien ilmaisuluokan taksonomia on paremmin havainnollistettu Venn-kaavalla seuraavasti:

Johtopäätös

Lvalue on lauseke, jonka arviointi määrittää objektin, bittikentän tai funktion identiteetin.

Prvalue on lauseke, jonka arviointi alustaa objektin tai bittikentän tai laskee operaattorin operandin arvon kontekstin määrittelemällä tavalla, jossa se esiintyy.

Xvalue on lvalue tai prvalue, sen lisäominaisuuden kanssa, että sen resursseja (tallennustilaa) voidaan käyttää uudelleen.

C ++ -määrittely kuvaa lausekeryhmän taksonomiaa puukaaviona, mikä osoittaa, että taksonomiassa on jonkin verran hierarkiaa. Tällä hetkellä taksonomiassa ei ole hierarkiaa, joten jotkut kirjoittajat käyttävät Venn-kaaviota, koska se kuvaa taksonomiaa paremmin kuin puukaavio.

OpenTTD Tutorial
OpenTTD is one of the most popular business simulation games out there. In this game, you need to create a wonderful transportation business. However,...
SuperTuxKart for Linux
SuperTuxKart is a great title designed to bring you the Mario Kart experience free of charge on your Linux system. It is pretty challenging and fun to...
Battle for Wesnoth Tutorial
The Battle for Wesnoth is one of the most popular open source strategy games that you can play at this time. Not only has this game been in developmen...