c++ könyv

Download C++ könyv

If you can't read please download the document

Upload: mucibuci88

Post on 15-Jun-2015

405 views

Category:

Documents


8 download

TRANSCRIPT

Bevezets Ez a bevezets ttekintst ad a C++ programozsi nyelv fo fogalmairl, tulajdonsgairl s standard (szabvny) knyvtrrl, valamint bemutatja a knyv szerkezett s elmagyarzza azt a megkzeltst, amelyet a nyelv lehetosgeinek s azok hasznlatnak lersnl alkalmaztunk. Ezenkvl a bevezeto fejezetek nmi httrinformcit is adnak a C+ +-rl, annak felptsrol s felhasznlsrl. Fejezetek 1. Megjegyzsek az olvashoz 2. Kirnduls a C++-ban 3. Kirnduls a standard knyvtrban

Megjegyzsek az olvashoz .Szlt a Rozmr: Van m elg, mirol meslni j: .... (L. Carroll . ford. Ttfalusi Istvn) A knyv szerkezete . Hogyan tanuljuk a C++-t? . A C++ jellemzoi . Hatkonysg s szerkezet . Filozfiai megjegyzs . Trtneti megjegyzs . Mire hasznljuk a C++-t? . C s C++ . Javaslatok C programozknak . Gondolatok a C++ programozsrl . Tancsok . Hivatkozsok 1.1. A knyv szerkezete A knyv hat rszbol ll: Bevezets: Az 1.3. fejezetek ttekintik a C++ nyelvet, az ltala tmogatott fo programoz si stlusokat, s a C++ standard knyvtrt. Elso rsz: A 4.9. fejezetek oktat jellegu bevezetst adnak a C++ beptett tpusair l s az alapszolgltatsokrl, melyekkel ezekbol programot pthetnk. Msodik rsz: A 10.15. fejezetek bevezetst adnak az objektumorientlt s az ltalnostott programozsba a C++ hasznlatval. 1

Harmadik rsz: A 16.22. fejezetek bemutatjk a C++ standard knyvtrt. Negyedik rsz: A 23.25. fejezetek tervezsi s szoftverfejlesztsi krdseket trgyalnak. Fggelkek: Az A.E fggelkek a nyelv technikai rszleteit tartalmazzk. Az 1. fejezet ttekintst ad a knyvrol, nhny tletet ad, hogyan hasznljuk, valamint httrinformcikat szolgltat a C++-rl s annak hasznlatrl. Az olvas btran tfuthat rajta, elolvashatja, ami rdekesnek ltszik, s visszatrhet ide, miutn a knyv ms rszeit elolvasta. A 2. s 3. fejezet ttekinti a C++ programozsi nyelv s a standard knyvtr fo fogalmait s nyelvi alaptulajdonsgait, megmutatva, mit lehet kifejezni a teljes C++ nyelvvel. Ha semmi mst nem tesznek, e fejezetek meg kell gyozzk az olvast, hogy a C++ nem (csupn) C, s hogy a C++ hossz utat tett meg e knyv elso s msodik kiadsa ta. A 2. fejezet magas szinten ismertet meg a C++-szal. A figyelmet azokra a nyelvi tulajdonsgokra irnytja, melyek tmogatjk az elvont adatbrzolst, illetve az objektumorientlt s az ltalnostott programozst. A 3. fejezet a standard knyvtr alapelveibe s fo szolgltatsaiba vezet be, ami lehetov teszi, hogy a szerzo a standard knyvtr szolgltatsait hasznlhassa a kvetkez o fejezetekben, valamint az olvasnak is lehetosget ad, hogy knyvtri szolgltatsokat hasznljon a gyakorlatokhoz s ne kelljen kzvetlenl a beptett, alacsony szintu tulajdons gokra hagyatkoznia. A bevezeto fejezetek egy, a knyv folyamn ltalnosan hasznlt eljrs pldjt adjk: ahhoz, hogy egy mdszert vagy tulajdonsgot mg kzvetlenebb s valszerubb mdon vizsg lhassunk, alkalmanknt eloszr rviden bemutatunk egy fogalmat, majd ksobb behat bban trgyaljuk azt. Ez a megkzelts lehetov teszi, hogy konkrt pldkat mutassunk be, mielott egy tmt ltalnosabban trgyalnnk. A knyv felptse gy tkrzi azt a megfigyel st, hogy rendszerint gy tanulunk a legjobban, ha a konkrttl haladunk az elvont fel . mg ott is, ahol visszatekintve az elvont egyszerunek s magtl rtetodonek ltszik. Az I. rsz a C++-nak azt a rszhalmazt rja le, mely a C-ben vagy a Pascalban kvetett hagyom nyos programozsi stlusokat tmogatja. Trgyalja a C++ programokban szereplo alapveto tpusokat, kifejezseket, vezrlsi szerkezeteket. A modularitst, mint a nvterek, forrsfjlok s a kivtelkezels ltal tmogatott tulajdonsgot, szintn trgyalja. Felttelezz k, hogy az olvasnak mr ismerosek az I. fejezetben hasznlt alapveto programozsi fogalmak, gy pldul bemutatjuk a C++ lehetosgeit a rekurzi s iterci kifejezsre, de nem sokig magyarzzuk, milyen hasznosak ezek. A II. rsz a C++ j tpusok ltrehozst s hasznlatt segto szolgltatsait rja le. Itt (10. s

12. fejezet) mutatjuk be a konkrt s absztrakt osztlyokat (felleteket), az opertor-tlterhel ssel (11. fejezet), a tbbalaksggal (polimorfizmussal) s az osztlyhierarchik hasz4 Bevezets

nlatval (12. s 15. fejezet) egytt. A 13. fejezet a sablonokat (template) mutatja be, vagyis a C++ lehetosgeit a tpus- s fggvnycsaldok ltrehozsra, valamint szemllteti a trol k elolltsra (pl. listk), valamint az ltalnostott (generikus) programozs tmogatsra hasznlt alapveto eljrsokat. A 14. fejezet a kivtelkezelst, a hibakezelsi mdszereket trgyalja s a hibaturs biztostshoz ad irnyelveket. Felttelezzk, hogy az olvas az objektumorient lt s az ltalnostott programozst nem ismeri jl, illetve hasznt ltn egy magyarzatnak, hogyan tmogatja a C++ a fo elvonatkoztatsi (absztrakcis) eljrsokat. gy teht nemcsak bemutatjuk az elvonatkoztatsi mdszereket tmogat nyelvi tulajdons gokat, hanem magukat az eljrsokat is elmagyarzzuk. A IV. rsz ebben az irnyban halad tovbb. A III. rsz a C++ standard knyvtrt mutatja be. Clja: megrtetni, hogyan hasznljuk a knyvtrat; ltalnos tervezsi s programozsi mdszereket szemlltetni s megmutatni, hogyan bovtsk a knyvtrat. A knyvtr gondoskodik trolkrl (kontnerek . list, vector, map, 18. s 19. fejezet), szabvnyos algoritmusokrl (sort, find, merge, 18. s 19. fejezet), karakterlnc-tpusokrl s -muveletekrol (20. fejezet), a bemenet s kimenet kezel srol (input/output, 21. fejezet), valamint a szmokkal vgzett muveletek (.numerikus szmts.) tmogatsrl (22. fejezet). A IV. rsz olyan krdseket vizsgl, melyek akkor merlnek fel, amikor nagy szoftverrendszerek tervezsnl s kivitelezsnl a C++-t hasznljuk. A 23. fejezet tervezsi s vezetsi krdsekkel foglalkozik. A 24. fejezet a C++ programozsi nyelv s a tervezsi krdsek kapcsolatt vizsglja, mg a 25. fejezet az osztlyok hasznlatt mutatja be a tervezsben. Az .A. fggelk a C++ nyelvtana, nhny jegyzettel. A .B. fggelk a C s a C++ kzti s a szabvnyos C++ (ms nven ISO C++, ANSI C++) illetve az azt megelozo C++vltozatok kzti rokonsgot vizsglja. A .C. fggelk nhny nyelvtechnikai pldt mutat be, A .D. fggelk pedig a kulturlis eltrsek kezelst tmogat standard knyvtrbeli elemeket mutatja be. Az .E. fggelk a standard knyvtr kivtelkezelsel kapcsolatos garanciit s kvetelmnyeit trgyalja. 1.1.1. Pldk s hivatkozsok Knyvnk az algoritmusok rsa helyett a program felptsre fekteti a hangslyt. Kvetkez skppen elkerli a ravasz vagy nehezebben rtheto algoritmusokat. Egy egyszeru eljrs alkalmasabb az egyes fogalmak vagy a programszerkezet egy szempontjnak szeml ltetsre. Pldul Shell rendezst hasznl, ahol a valdi kdban jobb lenne

gyorsrendez st (quicksort) hasznlni. Gyakran j gyakorlat lehet a kd jrarsa egy alkalmasabb algoritmussal. A valdi kdban ltalban jobb egy knyvtri fggvny hvsa, mint a knyvben hasznlt, a nyelvi tulajdonsgok szemlltetsre hasznlt kd. 1. Megjegyzsek az olvashoz 5

A tanknyvi pldk szksgszeruen egyoldal kpet adnak a programfejlesztsrol. Tisztzva s egyszerustve a pldkat a felmerlt bonyolultsgok eltunnek. Nincs, ami helyettesten a valdi programok rst, ha benyomst akarunk kapni, igazbl milyen is a programoz s s egy programozsi nyelv. Ez a knyv a nyelvi tulajdonsgokra s az alapveto eljrsokra sszpontost, amelyekbol minden program sszetevodik, valamint az sszepts szablyaira. A pldk megvlasztsa tkrzi fordtprogramokkal, alapknyvtrakkal, szimulcikkal jellemezheto htteremet. A pldk egyszerustett vltozatai a valdi kdban tallhatknak. Egyszerustsre van szksg, hogy a programozsi nyelv s a tervezs lnyeges szempontjai el ne vesszenek a rszletekben. Nincs .gyes. plda, amelynek nincs megfeleloje a val di kdban. Ahol csak lehetsges, a .C. fggelkben lvo nyelvtechnikai pldkat olyan alakra hoztam, ahol a vltozk x s y, a tpusok A s B, a fggvnyek f() s g() nevuek. A kdpldkban az azonostkhoz vltoz szlessgu betuket hasznlunk. Pldul: #include int main() { std::cout // nagyobb = // nagyobb vagy egyenlo rtkadsokban s aritmetikai muveletekben a C++ az alaptpusok kztt elvgez minden rtelmes talaktst, gy azokat egymssal tetszs szerint keverhetjk: 2. Kirnduls a C++-ban 31

void some_function() // rtket vissza nem ad fggvny { double d = 2.2; // lebegopontos szm kezdeti rtkadsa int i = 7; // egsz kezdeti rtkadsa d = d+i; // sszeg rtkadsa i = d*i; // szorzat rtkadsa } Itt = az rtkad muvelet jele s == az egyenlosget teszteli, mint a C-ben. 2.3.2. Elgazsok s ciklusok A C++ az elgazsok s ciklusok kifejezsre rendelkezik a hagyomnyos utastskszlettel. me egy egyszeru fggvny, mely a felhasznltl vlaszt kr s a vlasztl fggo logikai rtket ad vissza: bool accept() { cout > answer; // vlasz beolvassa if (answer == 'y') return true; return false; } A > (.olvasd be.) a bemenet muveleti jele, a cin a szabvnyos bemen o adatfolyam. A >> jobb oldaln ll kifejezs hatrozza meg, milyen bemenet fogadhat el s ez a beolvass clpontja. A \n karakter a kirt karakterlnc vgn j sort jelent. A plda kiss javthat, ha egy 'n' vlaszt is szmtsba vesznk: bool accept2() { cout > answer; // vlasz beolvassa 32 Bevezets

switch (answer) { case 'y': return true; case 'n': return false; default: cout answer; // vlasz beolvassa switch (answer) { case 'y': return true; case 'n': return false; default: cout > tugorja az reshely (whitespace) karaktereket, az ilyenekkel elvlasztott egszeket az albbi egyszeru ciklussal olvashatjuk be: int read_ints(vector& v) // feltlti v-t , visszatr a beolvasott egszek szmval { int i = 0; while (i>v[i]) i++; return i; } Ha a bemeneten egy nem egsz rtk jelenik meg, a bemeneti muvelet hibba tkzik, gy a ciklus is megszakad. Pldul ezt a bemenetet felttelezve: 1 2 3 4 5.6 7 8. a read_ints() fggvny t egsz szmot fog beolvasni: 1 2 3 4 5 A muvelet utn a bemeneten a kvetkezo beolvashat karakter a pont lesz. A nem lthat reshely (whitespace) karakterek meghatrozsa itt is ugyanaz, mint a szabvnyos C-ben (szkz, tabultor, jsor, fggoleges tabultorra illeszts, kocsivissza), s a fejllom nyban levo isspace() fggvnnyel ellenorizhetok valamely karakterre (20.4.2). Az istream objektumok hasznlatakor a leggyakoribb hiba, hogy a bemenet nem egszen abban a formtumban rkezik, mint amire felkszltnk, ezrt a bemenet nem trtnik meg. Ezrt mielott hasznlni kezdennk azokat az rtkeket, melyeket remnyeink szerint beolvastunk, ellenoriznnk kell a bemeneti adatfolyam llapott (21.3.3), vagy kivteleket kell hasznlnunk (21.3.6). A bemenethez hasznlt formtumot a helyi sajtossgok (locale) hatrozzk meg (21.7). Alaprtelmezs szerint a logikai rtkeket a 0 (hamis) s az 1 (igaz) rtk jelzi, az egszeket tzes szmrendszerben kell megadnunk, a lebegopontos szmok formja pedig olyan, ahogy a C++ programokban rhatjuk azokat. A basefield (21.4.2) tulajdonsg belltsval lehetosg van arra is, hogy a 0123 szmot a 83 tzes szmrendszerbeli szm oktlis alakjak nt, a 0xff bemenetet pedig a 255 hexadecimlis alakjaknt rtelmezzk. A mutatk beolvas shoz hasznlt formtum teljesen az adott nyelvi vltozattl fgg (nzznk utna, sajt fejlesztorendszernk hogyan mukdik). 21. Adatfolyamok 825

Meglepo mdon nincs olyan >> tagfggvny, mellyel egy karaktert olvashatnnk be. Ennek oka az, hogy a >> opertor a karakterekhez a get() karakter-beolvas fggvny (21.3.4) seg tsgvel knnyen megvalsthat, gy nem kell tagfggvnyknt szerepelnie. Az adatfolyamokr l sajt karaktertpusaiknak megfelelo karaktereket olvashatunk be. Ha ez a karaktert pus a char, akkor beolvashatunk signed char s unsigned char tpus adatot is: template basic_istream& operator>>(basic_istream&, Ch&); template basic_istream& operator>>(basic_istream&, unsigned char&); template basic_istream& operator>>(basic_istream&, signed char&); A felhasznl szempontjbl teljesen mindegy, hogy a >> tagfggvny vagy nll eljrs-e. A tbbi >> opertorhoz hasonlan ezek a fggvnyek is eloszr tugorjk a bevezeto reshely karaktereket: void f() { char c; cin >> c; // ... } Ez a kdrszlet az elso nem reshely karaktert a cin adatfolyambl a c vltozba helyezi. A beolvass clja lehet karaktertmb is: template basic_istream& operator>>(basic_istream&, Ch*); template basic_istream& operator>>(basic_istream&, unsigned char*); template basic_istream& operator>>(basic_istream&, signed char*); Ezek a muveletek is eldobjk a bevezeto reshely karaktereket, majd addig olvasnak, amg egy reshely karakter vagy fjlvge jel nem kvetkezik, vgl a karaktertmb vgre egy 0 karaktert rnak. Termszetesen ez a megolds alkalmat ad a tlcsordulsra, gy rdemesebb inkbb egy string objektumba (20.3.15) helyezni a beolvasott adatokat. Ha mgis az elobbi 826 A standard knyvtr

megoldst vlasztjuk, rgztsk, hogy legfeljebb hny karaktert akarunk beolvasni a >> oper tor segtsgvel. Az is.width(n) fggvnyhvssal azt hatrozzuk meg, hogy a kvetkezo, is bemeneti adatfolyamon vgrehajtott >> muvelet legfeljebb n-1 karaktert olvashat be: void g() { char v[4]; cin.width(4); cin >> v; cout >buf) os buf muvelet egy referencit ad vissza, amely az is adatfolyamra hivatkozik, a vizsglatot pedig az is::operator void*() muvelet vgzi: void f(istream& i1, istream& i2, istream& i3, istream& i4) { iocopy(i1,cout); // komplex szmok msolsa iocopy(i2,cout); // ktszeres pontossg lebegopontos szmok msolsa iocopy(i3,cout); // karakterek msolsa iocopy(i4,cout); // reshelyekkel elvlasztott szavak msolsa } 21.3.4. Karakterek beolvassa A >> opertor formzott bemenetre szolgl, teht adott tpus s adott formtum objektumok beolvassra. Ha erre nincs szksgnk s inkbb valban karakterekknt akarjuk beolvasni a karaktereket, hogy ksobb mi dolgozzuk fel azokat, hasznljuk a get() fggvnyeket: template class basic_istream : virtual public basic_ios { public: // ... // formzatlan bemenet streamsize gcount() const; // a legutbbi get() ltal beolvasott karakterek szma int_type get(); // egy Ch (vagy Tr::eof()) beolvassa basic_istream& get(Ch& c); // egy Ch olvassa c-be basic_istream& get(Ch* p, streamsize n); // jsor a lezrjel basic_istream& get(Ch* p, streamsize n, Ch term); 21. Adatfolyamok 829

basic_istream& getline(Ch* p, streamsize n); // jsor a lezrjel basic_istream& getline(Ch* p, streamsize n, Ch term); basic_istream& ignore(streamsize n = 1, int_type t = Tr::eof()); basic_istream& read(Ch* p, streamsize n); // legfeljebb n karakter beolvassa // ... }; Ezek mellett a fejllomny biztostja a getline() fggvnyt is, amely a szabvnyos string-ek (20.3.15) beolvassra hasznlhat. A get() s a getline() fggvnyek ugyangy kezelik az reshely karaktereket, mint brmely ms karaktert. Kifejezetten olyan adatok beolvassra szolglnak, ahol nem szmt a beolvasott karakterek jelentse. Az istream::get(char&) fggvny egyetlen karaktert olvas be paramterbe. Egy karakterenk nt msol programot pldul a kvetkezokppen rhatunk meg. int main() { char c; while(cin.get(c)) cout.put(c); } A hromparamteru s.get(p,n,term) legfeljebb n-1 karaktert olvas be a p[0],., p[n2] tmbbe. A get() az tmeneti trban mindenkppen elhelyez egy 0 karaktert a beolvasott karakterek utn, gy a p mutatnak egy legalbb n karakter mretu tmbre kell mutatnia. A harmadik paramter (term) az olvasst lezr karaktert hatrozza meg. A hromparamteru get() leggyakoribb felhasznlsi mdja az, hogy beolvasunk egy .sort. egy rgztett mretu trba s ksobb innen hasznljuk fel karaktereit: void f() { char buf[100]; cin >> buf; // gyans: tlcsordulhat cin.get(buf,100,'\n'); // biztonsgos // ... } Ha a get() megtallja a lezr karaktert, az adatfolyamban hagyja, teht a kvetkezo bemeneti muvelet ezt a karaktert kapja meg elsoknt. Soha ne hvjuk meg jra a get() fggvnyt a lezr karakter eltvoltsa nlkl. Ha egy get() vagy getline() fggvny egyetlen karaktert sem olvas s tvolt el az adatfolyamrl meghvdik setstate(failbit), gy a kvetkezo beolvas sok sikertelenek lesznek (vagy kivtel vltdik ki, 21.3.6). 830 A standard knyvtr

void subtle_error { char buf[256]; while (cin) { cin.get(buf,256); // a sor beolvassa cout (istream& s, complex& a) /* a complex tpus lehetsges bemeneti formtumai ("f" lebegopontos szm) f ( f ) ( f , f ) */ { 21. Adatfolyamok 833

double re = 0, im = 0; char c = 0; s >> c; if (c == '(') { s >> re >> c; if (c == ',') s >> im >> c; if (c != ')') s.clear(ios_base::failbit); // llapot belltsa } else { s.putback(c); s >> re; } if (s) a = complex(re,im); return s; } A nagyon kevs hibakezelo utasts ellenre ez a programrszlet szinte minden hibatpust kpes kezelni. A loklis c vltoznak azrt adunk kezdortket, hogy ha az elso >> muvelet sikertelen, nehogy vletlenl pont a ( karakter legyen benne. Az adatfolyam llapotnak ellenorzsre a fggvny vgn azrt van szksg, mert az a paramter rtkt csak akkor vltoztathatjuk meg, ha a korbbi muveleteket sikeresen vgrehajtottuk. Ha formzsi hiba trtnik az adatfolyam llapota failbit lesz. Azrt nem badbit, mert maga az adatfolyam nem srlt meg. A felhasznl a clear() fggvnnyel alapllapotba helyezheti az adatfolyamot s tovbblpve rtelmes adatokat nyerhet onnan. Az adatfolyam llapotnak belltsra szolgl fggvny neve clear(), mert ltalban arra hasznljuk, hogy az adatfolyam llapott good() rtkre lltsuk. Az ios_base::clear() (21.3.3) paramternek alaprtelmezett rtke ios_base::goodbit. 21.3.6. Kivtelek Nagyon knyelmetlen minden egyes I/O muvelet utn kln ellenorizni, hogy sikeres volte, ezrt nagyon gyakori hiba, hogy elfelejtnk egy ellenorzst ott, ahol felttlenl szksg van r. A kimeneti muveleteket ltalban nem ellenorzik, annak ellenre, hogy nha ott is elofordulhat hiba. Egy adatfolyam llapotnak kzvetlen megvltoztatsra csak a clear() fggvnyt hasznlhatjuk. Ezrt ha rteslni akarunk az adatfolyam llapotnak megvltozsrl, elg nyilvnval mdszer, hogy a clear() fggvnyt kivtelek kivltsra krjk. Az ios_base osztly exceptions() tagfggvnye pontosan ezt teszi: 834 A standard knyvtr

template class basic_ios : public ios_base { public: // ... class failure; // kivtelosztly (lsd 14.10) iostate exceptions() const; // kivtel-llapot kiolvassa void exceptions(iostate except); // kivtel-llapot belltsa // ... }; A kvetkezo utastssal pldul elrhetjk, hogy a clear() egy ios_base::failure kivtelt vltson ki, ha a cout adatfolyam bad, fail vagy eof llapotba kerl, vagyis ha valamelyik muvelet nem hibtlanul fut le: cout.exceptions(ios_base::badbit|ios_base::failbit|ios_base::eofbit); Ha szksg van r, a cout vizsglatval pontosan megllapthatjuk, milyen problma trt nt. Ehhez hasonlan a kvetkezo utastssal azokat a ritknak egyltaln nem nevezheto eseteket dolgozhatjuk fel, amikor a beolvasni kvnt adatok formtuma nem megfelelo, s ennek kvetkeztben a bemeneti muvelet nem ad vissza rtket: cin.exceptions(ios_base::badbit|ios_base::failbit); Ha az exceptions() fggvnyt paramterek nlkl hvjuk meg, akkor azokat az I/O llapotjelz oket adja meg, amelyek kivtelt vltanak ki: void print_exceptions(ios_base& ios) { ios_base::iostate s = ios.exceptions(); if (s&ios_base::badbit) cout s; utastssorozat egyenrtku az albbival: cout > s; Adott idoben minden adatfolyamhoz legfeljebb egy ostream objektum ktheto. Az s.tie(0) utastssal levlaszthatjuk az s objektumhoz kttt adatfolyamot (ha volt ilyen). A tbbi olyan adatfolyam-fggvnyhez hasonlan, melyek rtket lltanak be, a tie(s) is a korbbi rtket adja vissza, teht a legutbb ide kttt adatfolyamot, vagy ha ilyen nincs, akkor a 0 rtket. Ha a tie() fggvnyt paramterek nlkl hvjuk meg, akkor egyszeruen visszakapjuk az aktulis rtket, annak megvltoztatsa nlkl. A szabvnyos adatfolyamok esetben a cout hozz van ktve a cin bemenethez, a wcout pedig a wcin adatfolyamhoz. A cerr adatfolyamot felesleges lenne brmihez is hozzktni, mivel ehhez nincs tmeneti tr, a clog pedig nem vr felhasznli kzremukdst. 21. Adatfolyamok 837

21.3.8. Orszemek Amikor a > opertort a complex tpusra hasznltuk, egyltaln nem foglalkoztunk az sszekttt adatfolyamok (21.3.7) krdsvel, vagy azzal, hogy az adatfolyam llapotnak megvltozsa kivteleket okoz-e (21.3.6). Egyszeruen azt feltteleztk (s nem ok nlk l), hogy a knyvtr ltal knlt fggvnyek figyelnek helyettnk ezekre a problmkra. De hogyan kpesek erre? Nhny tucat ilyen fggvnnyel kell megbirkznunk, gy ha olyan bonyolult eljrsokat kellene ksztennk, amely az sszekttt adatfolyamokkal, a helyi sajtossgokkal (locale, 21.7, D), a kivtelekkel, s egyebekkel is foglalkoznak, akkor igen kusza kdot kapnnk. A megoldst a sentry (.orszem.) osztly bevezetse jelenti, amely a kzs kdrszleteket tartalmazza. Azok a rszek, melyeknek elsoknt kell lefutniuk (a .prefix kd., pldul egy lekttt adatfolyam kirtse), a sentry konstruktorban kaptak helyet. Az utolsknt fut sorokat (a .suffix kdokat., pldul az llapotvltozsok miatt elvrt kivtelek kivltst) a sentry destruktora hatrozza meg: template class basic_ostream : virtual public basic_ios { // ... class sentry; // ... }; template class basic_ostream::sentry { public: explicit sentry(basic_ostream& s); ~sentry(); operator bool(); // ... }; Teht egy ltalnos kdot rtunk, melynek segtsgvel az egyes fggvnyek a kvetkezo formba rhatk: template basic_ostream& basic_ostream::operators>>x) try { current = m.insert(current,make_pair(s,x)); } catch(...) { // itt a "current" mg mindig az aktulis elemet jelli } } E. Kivtelbiztossg a standard knyvtrban 1289

E.4.2. Garancik s kompromisszumok Az alapbiztostson tli szolgltatsok sszevisszasgai a megvalstsi lehetosgekkel magyar zhatk. A programozk azt szeretnk leginkbb, hogy mindenhol eros biztosts lljon rendelkezskre a leheto legkevesebb korltozs mellett, de ugyanakkor azt is elvrjk, hogy a standard knyvtr minden muvelete optimlisan hatkony legyen. Mindkt elvrs jogos, de sok muvelet esetben lehetetlen egymssal prhuzamosan megvalstani. Ahhoz, hogy jobban megvilgtsuk az elkerlhetetlen kompromisszumokat, megvizsgljuk, milyen mdokon lehet egy vagy tbb elemet felvenni egy listba, vektorba vagy map-be. Nzzk eloszr, hogy egy elemet hogyan vihetnk be egy listba vagy egy vektorba. Szok s szerint, a push_back() nyjtja a legegyszerubb lehetosget: void f(list& lst, vector& vec, const X& x) { try { lst.push_back(x); // hozzads a listhoz } catch (...) { // lst vltozatlan return; } try { vec.push_back(x); // hozzads a vektorhoz } catch (...) { // vec vltozatlan return; } // lst s vec egy-egy x rtku j elemmel rendelkezik } Az eros biztosts megvalstsa ez esetben egyszeru s .olcs.. Az eljrs azrt is hasznos, mert teljesen kivtelbiztos megoldst ad az elemek felvtelre. A push_back() azonban asszociatv trolkra nem meghatrozott: a map osztlyban nincs back(). Egy asszociatv trol esetben az utols elemet a rendezs hatrozza meg, nem a pozci. Az insert() fggvny garancii mr kicsit bonyolultabbak. A gondot az jelenti, hogy az insert() muveletnek gyakran kell egy elemet a trol .kzepn. elhelyeznie. Lncolt adatszerkezetekn l ez nem jelent problmt, teht a list s a map egyszeruen megvalsthat, a vector esetben azonban elore lefoglalt terlet ll rendelkezsnkre, a vector::insert() fggvny egy tlagos megvalstsa pedig a beszrsi pont utni elemeket thelyezi, hogy helyet csinljon az j elem szmra. Ez az optimlis megolds, de arra nincs egyszeru md1290 Fggelkek s trgymutat

szer, hogy a vektort visszalltsuk eredeti llapotba, ha valamelyik elem msol rtkadsa vagy msol konstruktora kivtelt vlt ki (lsd E.8[10-11]), ezrt a vector azzal a felttellel ad biztostsokat, hogy az elemek msol konstruktora nem vlt ki kivtelt. A list s a map osztlynak nincs szksge ilyen korltozsra, ezek knnyedn be tudjk illeszteni az j elemet a szksges msolsok elvgzse utn. Pldakppen ttelezzk fel, hogy az X msol konstruktora s msol rtkadsa egy X::cannot_copy kivtelt vlt ki, ha valamilyen okbl nem sikerl ltrehoznia a msolatot: void f(list& lst, vector& vec, map& m, const X& x, const string& s) { try { lst.insert(lst.begin(),x); // hozzads a listhoz } catch (...) { // lst vltozatlan return; } try { vec.insert(vec.begin(),x); // hozzads a vektorhoz } catch (X::cannot_copy) { // hopp: vec vagy rendelkezik, vagy nem rendelkezik j elemmel return; } catch (...) { // vec vltozatlan return; } try { m.insert(make_pair(s,x)); // hozzads az asszociatv tmbhz } catch (...) { // m vltozatlan return; } // lst s vec egy-egy x rtku j elemmel rendelkezik // m egy j (s,x) rtku elemmel rendelkezik } Ha X::cannot_copy kivtelt kapunk, nem tudhatjuk, hogy az j elem bekerlt-e a vec trol ba. Ha sikerlt beilleszteni az elemet, az rvnyes llapotban lesz, de pontos rtkt nem ismerjk. Az is elkpzelheto, hogy egy X::cannot_copy kivtel utn nhny elem .titokzaE. Kivtelbiztossg a standard knyvtrban 1291

tosan. megkettozodik (lsd E.8[11]), msik megvalstst alkalmazva pedig a vektor vgn lvo elemek tunhetnek el, mert csak gy lehet biztostani, hogy a trol rvnyes llapotban maradjon s ne szerepeljenek benne rvnytelen elemek. Sajnos az eros biztosts megvalstsa a vector osztly insert() fggvnye esetben lehetetlen, ha megengedjk, hogy az elemek msol konstruktora kivtelt vltson ki. Ha egy vektorban teljesen meg akarnnk vdeni magunkat az elemek thelyezse kzben keletkezo kivtelektol, a kltsgek elviselhetetlenl megnonnek az egyszeru, alapbiztostst nyjt megoldshoz kpest. Sajnos nem ritkk az olyan elemtpusok, melyek msol konstruktora kivtelt eredmnyezhet. Mr a standard knyvtrban is tallhatunk pldt: a vector, a vector< vector > s a map is ilyen. A list s a vector trol ugyanolyan biztostst ad az insert() egyelemu s tbbelemu vltozat hoz, mert azok megvalstsi mdja azonos. A map viszont eros biztostst ad az egyelem u beszrshoz, mg a tbbelemuhz csak alapbiztostst. Az egyelemu insert() a map esetben knnyen elksztheto eros biztostssal, a tbbelemu vltozat egyetlen logikus megvalstsi mdja azonban a map esetben az, hogy az j elemeket egyms utn szrjuk be, s ehhez mr nagyon nehz lenne eros garancikat adni. A gondot itt az jelenti, hogy nincs egyszeru visszalpsi lehetosg (nem tudunk korbbi sikeres beszrsokat visszavonni), ha valamelyik elem beszrsa nem sikerl. Ha olyan tbbelemu beszr muveletre van szksgnk, amely eros biztostst ad, azaz vagy minden elemet hibtlanul beilleszt, vagy egyltaln nem vltoztatja meg a trolt, legegyszer ubben gy valsthatjuk meg, hogy egy teljesen j trolt ksztnk, majd ennek sikeres ltrehozsa utn egy swap() muveletet alkalmazunk: template void safe_insert(C& c, typename C::const_iterator i, Iter begin, Iter end) { C tmp(c.begin(),i); // az ell levo elemek msolsa ideiglenes vltozba copy(begin,end,inserter(tmp,tmp.end())); // j elemek msolsa copy(i,c.end(),inserter(tmp,tmp.end())); // a zr elemek msolsa swap(c,tmp); } Szoks szerint, ez a fggvny is hibsan viselkedhet, ha az elemek destruktora kivtelt vlt ki, ha viszont az elemek msol konstruktora okoz hibt, a paramterben megadott trol vltozatlan marad. 1292 Fggelkek s trgymutat

E.4.3. A swap() A msol konstruktorokhoz s rtkadsokhoz hasonlan a swap() eljrsok is nagyon fontos szerepet jtszanak sok szabvnyos algoritmusban s kzvetlenl is gyakran hasznljk a felhasznlk. A sort() s a stable_sort() pldul ltalban a swap() segtsgvel rendezi t az elemeket. Teht ha a swap() kivtelt vlt ki, mikzben a trolban szereplo rtkeket cserlgeti, akkor a trol elemei a csere helyett vagy vltozatlanok maradnak, vagy megkett ozodnek. Vizsgljuk meg a standard knyvtr swap() fggvnynek albbi, egyszeru megvalstst (18.6.8): template void swap(T& a, T& b) { T tmp = a; a = b; b = tmp; } Erre teljesl, hogy a swap() csak akkor eredmnyezhet kivtelt, ha azt az elemek msol konstruktora vagy msol rtkadsa vltja ki. Az asszociatv trolktl eltekintve a szabvnyos trolk biztostjk, hogy a swap() fggv ny ne vltson ki kivteleket. A trolkban ltalban gy is meg tudjuk valstani a swap() fggvnyt, hogy csak az adatszerkezeteket cserljk fel, melyek mutatknt szolglnak a tnyleges elemekhez (13.5, 17.1.3). Mivel gy magukat az elemeket nem kell mozgatnunk, azok konstruktorra vagy rtkad muveletre nincs szksgnk, teht azok nem kapnak lehetosget kivtel kivltsra. Ezenkvl a szabvny biztostja, hogy a knyvtr swap() fggvnye nem tesz rvnytelenn egyetlen hivatkozst, mutatt s bejrt sem azok kzl, melyek a felcserlt trolk elemeire hivatkoznak. Ennek kvetkeztben kivtelek egyetlen ponton lphetnek fel: az asszociatv trolk sszehasonlt objektumaiban, melyeket az adatszerkezet lerjnak rszeknt kell msolnunk. Teht az egyetlen kivtel, amit a szabvnyos trolk swap() eljrsa eredmnyezhet, az sszehasonlt objektum msol konstruktorbl vagy rtkad muveletbol szrmazik (17.1.4.1). Szerencsre az sszehasonlt objektumoknak ltalban annyira egyszeru msol muveleteik vannak, hogy nincs lehetosgk kivtel kivltsra. A felhasznli swap() fggvnyek viszonylag egyszeruen nyjthatnak ugyanilyen biztostsokat, ha gondolunk r, hogy .mutatkkal. brzolt adatok esetben elegendo csak a mutat kat felcserlnnk, ahelyett, hogy lassan s preczen lemsolnnk a mutatk ltal kijellt tnyleges adatokat (13.5, 16.3.9, 17.1.3). E. Kivtelbiztossg a standard knyvtrban 1293

E.4.4. A kezdeti rtkads s a bejrk Az elemek szmra val memriafoglals s a memriaterletek kezdeti rtkadsa alapvet o rsze minden trolnak (E.3). Ebbol kvetkezik, hogy a fel nem tlttt (eloksztetlen) memriaterleten objektumot ltrehoz szabvnyos eljrsok . az uninitialized_fill(), az uninitialized_fill_n() s az uninitialized_copy() (19.4.4) . semmikppen sem hagyhatnak ltrehozott objektumokat a memriban, ha kivtelt vltanak ki. Ezek az algoritmusok eros biztostst valstanak meg (E.2), amihez gyakran kell elemeket trlni, teht az a kvetelm ny, miszerint a destruktoroknak tilos kivtelt kivltaniuk, elengedhetetlen ezeknl a fggvnyeknl is (lsd E.8[14]). Ezenkvl azoknak a bejrknak is megfeleloen kell viselkedni k, melyeket paramterknt adunk t ezeknek az eljrsoknak. Teht rvnyes bej rknak kell lennik, rvnyes sorozatokra kell hivatkozniuk, s a bejr muveleteknek (pldul a ++, a != vagy a * opertornak) nem szabad kivtelt kivltaniuk, ha rvnyes bej rkra alkalmazzuk azokat. A bejrk (itertorok) olyan objektumok, melyeket a szabvnyos algoritmusok s a szabvnyos trolk muveletei szabadon lemsolhatnak, teht ezek msol konstruktora s msol rtkadsa nem eredmnyezhet kivtelt. A szabvny garantlja, hogy a szabvnyos trol k ltal visszaadott bejrk msol konstruktora s msol rtkadsa nem vlt ki kivtelt, gy a vector::begin() ltal visszaadott bejrt pldul nyugodtan lemsolhatjuk, nem kell kivteltol tartanunk. Figyeljnk r, hogy a bejrkra alkalmazott ++ vagy -- muvelet eredmnyezhet kivtelt. Pld ul egy istreambuf_iterator (19.2.6) egy bemenethibt (logikusan) egy kivtel kivltsval jelezhet, egy tartomnyellenorztt bejr pedig teljesen szablyosan jelezheti kivtellel azt, hogy megprbltunk kilpni a megengedett tartomnybl (19.3). Akkor azonban nem eredmnyezhetnek kivtelt, ha a bejrt gy irnytjuk t egy sorozat egyik elemrol a msikra, hogy kzben a ++ vagy a -- egyetlen szablyt sem srtjk meg. Teht az uninitialized_fill(), az uninitialized_fill_n() s az uninitialized_copy() felttelezi, hogy a bejrkra alkalmazott ++ s -- muvelet nem okoz kivtelt. Ha ezt mgis megteszik, a szabv ny megfogalmazsa szerint ezek nem is igazn bejrk, vagy az ltaluk megadott .sorozat . nem rtelmezheto sorozatknt. Most is igaz, hogy a szabvny nem kpes megvdeni a felhasznlt a sajt maga ltal okozott nem meghatrozhat viselkedstol (E.2). E.4.5. Hivatkozsok elemekre Ha elemre hivatkoz mutatt, referencit vagy bejrt adunk t egy eljrsnak, az tnkreteheti

a listt azzal, hogy az adott elemet rvnytelenn teszi: 1294 Fggelkek s trgymutat

void f(const X& x) { list lst; lst.push_back(x); list::iterator i = lst.begin(); *i = x; // x listba msolsa // ... } Ha az x vltozban rvnytelen rtk szerepel, a list destruktora nem kpes hibtlanul megsemmis teni az lst objektumot: struct X { int* p; X() { p = new int; } ~X() { delete p; } // ... }; void malicious() { X x; x.p = reinterpret_cast(7); // hibs x f(x); // idoztett bomba } Az f() vgrehajtsnak befejeztvel meghvdik a list destruktora, amely viszont megh vja az X destruktort egy rvnytelen rtkre. Ha megprbljuk a delete p parancsot vgrehajtani egy olyan p rtkre, amely nem 0 s nem is ltezo X tpus rtkre mutat, az eredm ny nem meghatrozhat lesz s akr a rendszer azonnali sszeomlst okozhatja. Egy msik lehetosg, hogy a memria rvnytelen llapotba kerl, ami sokkal ksobb, a program olyan rszben okoz .megmagyarzhatatlan. hibkat, amely teljesen fggetlen a tnyleges problmtl. Ez a hibalehetosg nem gtolja meg a programozkat abban, hogy referencikat s bejrkat hasznljanak a trolk elemeinek kezelsre, hiszen mindenkppen ez az egyik legegyszer ubb s leghatkonyabb mdszer az ilyen feladatok elvgzshez. Mindenesetre rdemes klnsen elovigyzatosnak lennnk a trolk elemeire val hivatkozsokkal kapcsolatban. Ha egy trol psge veszlybe kerlhet, rdemes a kevsb gyakorlott felhaszn lk szmra biztonsgosabb, ellenorztt vltozatokat is ksztennk, pldul megadhatunk egy olyan eljrst, amely ellenorzi, hogy az j elem rvnyes-e, mielott beszrja azt a .fontos. trolba. Termszetesen ilyen ellenorzseket csak akkor vgezhetnk, ha pontosan ismerjk a trolban trolt elemek tpust. E. Kivtelbiztossg a standard knyvtrban 1295

ltalban, ha egy trol valamelyik eleme rvnytelenn vlik, a trolra alkalmazott minden tovbbi muvelet hibkat eredmnyezhet. Ez nem csak a trolk sajtja: brmely objektum, amely valamilyen szempontbl hibs llapotba kerl, a ksobbiekben brmikor okozhat problmkat. E.4.6. Prediktumok Szmos szabvnyos algoritmus s trol hasznl olyan prediktumokat, melyeket a felhaszn lk adhatnak meg. Az asszociatv trolk esetben ezek klnsen fontos szerepet tltenek be: az elemek keresse s beszrsa is ezen alapul. A szabvnyos trolk muveletei ltal hasznlt prediktumok is okozhatnak kivteleket, s ha ez bekvetkezik, a standard knyvtr muveletei legalbb alapbiztostst nyjtanak, de sok esetben (pldul az egyelemu insert() muveletnl) eros biztosts ll rendelkezsnkre (E.4.1). Ha egy troljn vgzett muvelet kzben egy prediktum kivtelt vlt ki, elkpzelhet o, hogy az ott trolt elemek nem pontosan azok lesznek, amelyeket szeretnnk, de mindenkppen rvnyes elemek. Pldul ha az == okoz kivtelt a list::unique() (17.2.2.3) muvelet vgrehajtsa kzben, nem vrhatjuk el, hogy minden rtkismtlods eltunjn. A felhasznl mindssze annyit felttelezhet, hogy a listban szereplo rtkek rvnyesek maradnak (lsd E.5.3). Szerencsre a prediktumok ritkn csinlnak olyasmit, ami kivtelt eredmnyezhet. Ennek ellenre a felhasznli szerkezetet kell hasznlnunk. Ez a megolds az egsz programot rugalmasabb teszi. Amikor j programot ksztnk, lehetosgnk van arra, hogy tgondoltabb megkzeltst talljunk s biztostsuk, hogy eroforrsainkat olyan osztlyokkal brzoljuk, melyek invarinsa alapbiztostst nyjt (E.2). Egy ilyen rendszerben lehetosg nylik arra, hogy kivlasszuk a ltfontossg objektumokat s ezek muveleteihez visszagrgetsi

mdszereket alkalmazzunk (azaz eros biztostst adhatunk . nhny egyedi felttel mellett). E. Kivtelbiztossg a standard knyvtrban 1301

A legtbb program tartalmaz olyan adatszerkezeteket s programrszeket, melyeket a kivtelbiztossgra nem gondolva rtak meg. Ha szksg van r, ezek a rszek egy kivtelbiztos keretbe gyazhatk. Az egyik lehetosg, hogy biztostjuk, hogy kivtelek ne kvetkezzenek be (ez trtnt a C standard knyvtrval, E.5.5), a msik megolds pedig az, hogy felletoszt lyokat hasznlunk, melyekben a kivtelek viselkedse s az eroforrsok kezelse pontosan meghatrozhat. Amikor olyan j tpusokat terveznk, amelyek kivtelbiztos krnyezetben futnak majd, kln figyelmet kell szentelnnk azoknak az eljrsoknak, melyeket a standard knyvtr hasznlni fog: a konstruktoroknak, a destruktoroknak, az rtkadsoknak, sszehasonltsoknak, swap fggvnyeknek, a prediktumknt hasznlt fggvnyeknek s a bejrkat kezel o eljrsoknak. Ezt legknnyebben gy valsthatjuk meg, hogy egy j osztlyinvarinst hatrozunk meg, amelyet minden konstruktor knnyedn biztosthat. Nha gy kell megtervezn nk az osztlyinvarinst, hogy az objektumoknak legyen egy olyan llapota, melyben egyszeruen trlhetok, ha egy muvelet .kellemetlen. helyen tkzik hibba. Idelis esetben ez az llapot nem egy mestersgesen megadott rtk, amit csak a kivtelkezels miatt kellett bevezetni, hanem az osztly termszetbol kvetkezo llapot (E.3.5). Amikor kivtelbiztossggal foglalkozunk, a fo hangslyt az objektumok rvnyes llapotainak (invarinsainak) meghatrozsra s az eroforrsok megfelelo felszabadtsra kell helyezn nk. Ezrt nagyon fontos, hogy az eroforrsokat kzvetlenl osztlyokkal brzoljuk. A vector_base (E.3.2) ennek egyszeru pldja. Az ilyen eroforrs-osztlyok konstruktora alacsonyszint u eroforrsokat foglal le (pldul egy memriatartomnyt a vector_base esetben), s invarinsokat llt be (pldul a mutatkat a megfelelo helyekre lltja a vector_base oszt lyban). Ezen osztlyok destruktora egyszeruen felszabadtja a lefoglalt eroforrst. A rszleges ltrehozs szablyai (14.4.1) s a .kezdeti rtkads az eroforrs lefoglalsval. mdszer (14.4) alkalmazsa lehetov teszi, hogy az eroforrsokat gy kezeljk. Egy jl megrt konstruktor minden objektum esetben belltja a megfelelo invarinst (24.3.7.1), teht a konstruktor olyan rtket ad az objektumnak, amely lehetov teszi, hogy a tovbbi muveleteket egyszeruen meg tudjuk rni s sikeresen vgre tudjuk hajtani. Ebbol kvetkezik, hogy a konstruktoroknak gyakran kell eroforrst lefoglalniuk. Ha ezt nem tudj k elvgezni, kivtelt vlthatnak ki, gy az objektum ltrehozsa elott foglalkozhatunk a jelentkez o problmkkal. Ezt a megkzeltst a nyelv s a standard knyvtr kzvetlenl t-

mogatja (E.3.5). Az a kvetelmny, hogy az eroforrsokat fel kell szabadtanunk s az operandusokat rvnyes llapotban kell hagynunk a kivtel kivltsa elott, azt jelenti, hogy a kivtelkezels terheit megosztjuk a kivtelt kivlt fggvny, a hvsi lncban levo fggvnyek s a kivtelt tnylegesen kezelo eljrs kztt. Egy kivtel kivltsa nem azt a hibakezelsi stlust jelen1302 Fggelkek s trgymutat

ti, hogy .hagyjuk az egszet valaki msra.. Minden fggvnynek, amely kivtelt vlt ki vagy ad tovbb, ktelessge felszabadtani azokat az eroforrsokat, melyek hatskrbe tartoznak, operandusait pedig megfelelo rtkre kell lltania. Ha az eljrsok ezt a feladatot nem kpesek vgrehajtani, a kivtelkezelo nemigen tehet mst, minthogy megprblja .szpen. befejezni a program mukdst. E.7. Tancsok [1] Legynk tisztban azzal, milyen szintu kivtelbiztossgra van szksgnk. E.2. [2] A kivtelbiztossgnak egy teljes kru hibatursi stratgia rsznek kell lennie. E.2. [3] Az alapbiztostst minden osztlyhoz rdemes megvalstani, azaz az invarinsokat mindig tartsuk meg s az eroforrs-lyukakat mindig kerljk el. E.2, E.3.2, E.4. [4] Ahol lehetosg s szksg van r, valstsunk meg eros biztostst, azaz egy muvelet vagy sikeresen hajtdjon vgre, vagy minden operandust hagyja vltozatlanul. E.2, E.3. [5] Destruktorokban ne fordulhasson elo kivtel. E.2, E.3.2, E.4. [6] Ne vltson ki kivtelt egy rvnyes sorozatban mozg bejr. E.4.1, E.4.4. [7] A kivtelbiztossg foglalja magban az nll muveletek alapos vizsglatt. E.3. [8] A sablon osztlyokat gy tervezzk meg, hogy azok .tltszak. legyenek a kiv telek szmra. E.3.1. [9] Az init() fggvny helyett hasznljunk konstruktort az eroforrsok lefoglalshoz. E.3.5. [10] Adjunk meg invarinst minden osztlyhoz, hogy ezzel pontosan meghatrozzuk rvnyes llapotaikat. E.2, E.6. [11] Gyozodjnk meg rla, hogy objektumaink mindig rvnyes llapotba llthatk anlkl, hogy kivtelektol kellene tartanunk. E.3.2, E.6. [12] Az invarinsok mindig legyenek egyszeruek. E.3.5. [13] Kivtel kivltsa elott minden objektumot lltsunk rvnyes llapotba. E.2, E.6. [14] Kerljk el az eroforrs-lyukakat. E.2, E.3.1, E.6. [15] Az eroforrsokat kzvetlenl brzoljuk. E.3.2, E.6. [16] Gondoljunk r, hogy a swap() fggvny gyakran hasznlhat az elemek msol sa helyett. E.3.3. E. Kivtelbiztossg a standard knyvtrban 1303

[17] Ha lehetosg van r, a try blokkok hasznlata helyett a muveletek sorrendjnek j megvlasztsval kezeljk a problmkat. E.3.4. [18] Ne trljk a .rgi. informcikat addig, amg a helyettesto adatok nem vlnak biztonsgosan elrhetov. E.3.3, E.6. [19] Hasznljuk a .kezdeti rtkads az eroforrs megszerzsvel. mdszert. E.3, E.3.2, E.6. [20] Vizsgljuk meg, hogy asszociatv trolinkban az sszehasonlt muveletek msolhatk-e. E.3.3. [21] Keressk meg a ltfontossg adatszerkezeteket s ezekhez adjunk meg olyan muveleteket, melyek eros biztostst adnak. E.6. E.8. Gyakorlatok 1. (*1) Soroljuk fel az sszes kivtelt, amely elofordulhat az E.1 pont f() fggvnyben. 2. (*1) Vlaszoljunk az E.1 pontban, a plda utn szereplo krdsekre. 3. (*1) Ksztsnk egy Tester osztlyt, amely idonknt a legalapvetobb muveletekben okoz kivtelt, pldul a msol konstruktorban. A Tester osztly segtsgvel prbljuk ki sajt standard knyvtrunk trolit. 4. (*1) Keressk meg a hibt az E.3.1 pontban szereplo vector konstruktornak rendezetlen vltozatban s rjunk programot, amely tnkreteszi az osztlyt. Ajnls: eloszr rjuk meg a vector destruktort. 5. (*2) Ksztsnk egyszeru listt, amely alapbiztostst nyjt. llaptsuk meg nagyon pontosan, milyen kvetelmnyeket kell a felhasznlnak teljestenie a biztos ts megvalstshoz. 6. (*3) Ksztsnk egyszeru listt, amely eros biztostst nyjt. Alaposan ellenorizz k az osztly mukdst. Indokoljuk meg, mirt tartjuk ezt a megoldst biztons gosabbnak. 7. (*2.5)rjuk jra a 11.12 String osztlyt gy, hogy ugyanolyan biztonsgos legyen, mint a szabvnyos trolk. 8. (*2) Hasonltsuk ssze a vector osztlyban meghatrozott rtkads s a safe_assign() fggvny klnbzo vltozatait a futsi ido szempontjbl. (E.3.3) 9. (*1.5) Msoljunk le egy memriafoglalt az rtkad opertor hasznlata nlkl (hiszen az operator=() megvalstshoz erre van szksgnk az E.3.3 pontban). 1304 Fggelkek s trgymutat

10. (*2) rjunk a vector osztlyhoz alapbiztostssal egy egyelemu s egy tbbelemu erase(), illetve insert() fggvnyt.E.3.2. 11. (*2) rjunk a vector osztlyhoz eros biztostssal egy egyelemu s egy tbbelemu erase(), illetve insert() fggvnyt (E.3.2). Hasonltsuk ssze ezen fggvnyek kltsgt s bonyolultsgt az elozo feladatban szereplo fggvnyekvel. 12. (*2) Ksztsnk egy safe_insert() fggvnyt (E.4.2), amely egy ltezo vector objektumba szr be elemet (nem pedig egy ideiglenes vltozt msol le). Milyen kiktseket kell tennnk a muveletekre? 13. (*2.5) Hasonltsuk ssze mret, bonyolultsg s hatkonysg szempontjbl a 12. s a 13. feladatban szereplo safe_insert() fggvnyt az E.4.2 pontban bemutatott safe_insert() fggvnnyel. 14. (*2.5) rjunk egy jobb (gyorsabb s egyszerubb) safe_insert() fggvnyt, kifejezetten asszociatv trolkhoz. Hasznljuk a traits eljrst egy olyan safe_insert() megvalstshoz, amely automatikusan kivlasztja az adott trolhoz optimlis megvalstst. Ajnls: 19.2.3. 15. (*2.5) Prbljuk megrni az uninitialized_fill() fggvnyt (19.4.4, E.3.1) gy, hogy az megfeleloen kezelje a kivteleket kivlt destruktorokat is. Lehetsges ez? Ha igen, milyen ron? Ha nem, mirt nem? 16. (*2.5) Keressnk egy trolt egy olyan knyvtrban, amely nem tartozik a szabv nyhoz. Nzzk t dokumentcijt s llaptsuk meg, milyen kivtelbiztossgi lehetosgek llnak rendelkezsnkre. Vgezznk nhny tesztet, hogy megllap tsuk, mennyire rugalmas a trol a memriafoglalsbl vagy a felhasznl ltal megadott programrszekbol szrmaz kivtelekkel szemben. Hasonltsuk ssze a tapasztaltakat a standard knyvtr megfelelo troljnak szolgltatsaival. 17. (*3) Prbljuk optimalizlni az E.3 pontban szereplo vector osztlyt a kivtelek lehetosgnek figyelmen kvl hagysval. Pldul trljnk minden try blokkot. Hasonltsuk ssze az gy kapott vltozat hatkonysgt a standard knyvtr vector osztlynak hatkonysgval. Hasonltsuk ssze a kt vltozatot mret s bonyolultsg szempontjbl is. 18. (*1) Adjunk meg invarinst a vector osztly (E.3) szmra gy, hogy megengedj k, illetve megtiltjuk a v==0 esetet (E.3.5). 19. (*2.5) Nzzk vgig egy vector osztly megvalstsnak forrskdjt. Milyen biztosts ll rendelkezsnkre az rtkadsban, a tbbelemu insert() utastsban s a resize() fggvnyben? 20. (*3) rjuk meg a hash_map (17.6) olyan vltozatt, amely ugyanolyan biztonsgos, mint a szabvnyos trolk. E. Kivtelbiztossg a standard knyvtrban 1305