Professional Documents
Culture Documents
C++ Konyv
C++ Konyv
{n!, , IU5U IU
{n!, , IU5I I445
{n!, , IU52 o7U
A fggelk tovbbi rsznek legjavt annak szenteljk, hogy lerjuk, milyen nyelvi tulajdon-
sgok teszik ezt lehetv, illetve hogy elmagyarzzuk, hogyan hasznljuk azokat. Jegyez-
zk meg, hogy a programozk tbbsgnek nem kell rszletekbe menen foglalkoznia
a loklokkal vagy kifejezetten azokat kezel kdot rnia. Akik mgis megteszik, azok is leg-
inkbb egy szabvnyos !oa!-t fognak elkeresni, hogy az adott adatfolyamnak elrjk an-
nak hasznlatt (21.7). Azok az eljrsok azonban, melyekkel a loklokat ltrehozhatjuk s
hasznlatukat egyszerv tehetjk, sajt programnyelvet alkotnak.
Ha egy program vagy rendszer sikeres, olyanok is hasznlni fogjk, akiknek az ignye s
zlse eltr attl, amire az eredeti tervezk s programozk szmtottak. A legtbb sikeres
programot hasznlni fogjk azokban az orszgokban is, ahol a (termszetes) nyelvek s ka-
rakterkszletek eltrnek az eredeti tervezk s programozk ltal ismertektl. Egy program
szleskr hasznlata a siker jele, ezrt a nyelvi s kulturlis hatrok kztt tvihet prog-
ramok tervezse s rsa a sikerre val felkszlst jelenti.
A nemzetkzi tmogats fogalma egyszer, a gyakorlati megszortsok azonban a !oa!
objektumok elksztst meglehetsen bonyolultt teszik:
1. A loklok az olyan helyi sajtossgokat tartalmazzk, mint a dtumok megjele-
nsi formja. A szablyok azonban egy adott kultrn bell is szmos apr s
D. Helyi sajtossgok 1177
nem rendszerezhet mdon eltrhetnek. A helyi szoksoknak semmi kzk
a programnyelvekhez, ezrt egy programnyelv nem szabvnyosthatja azokat.
2. A lokloknak bvthetnek kell lennik, mert nem lehetsges az sszes helyi
sajtossgot felsorolni, amely minden C++ felhasznlnak fontos.
3. A !oa! objektumokat olyan I/O mveletekben hasznljuk, melyeknl a futsi
id igen fontos.
4. A !oa! objektumoknak lthatatlannak kell lennik a legtbb programoz sz-
mra, hiszen k anlkl szeretnk kihasznlni a megfelel dolgot vgz adat-
folyam-bemenetet s -kimenetet, hogy pontosan ismernk annak felptst,
megvalstst.
5. A lokloknak elrhetnek kell lennik azok szmra, akik olyan eszkzket ter-
veznek, amelyek helyi sajtossgoktl fgg adatokat kezelnek az adatfolyam
I/O knyvtr keretein kvl.
Egy bemeneti s kimeneti mveleteket vgz program tervezsekor vlasztanunk kell,
hogy a kimenet formtumt szoksos kddal vagy !oa!-ek felhasznlsval vezreljk-
e. Az elbbi (hagyomnyos) megkzelts ott clszer, ahol biztostani tudjuk, hogy min-
den bemeneti mveletet knnyen t lehet alaktani a helyi sajtossgoknak megfelelen.
Ha azonban a beptett tpusok megjelensnek kell vltoznia, ha klnbz karakterksz-
letekre van szksg, vagy ha a bemenetre/kimenetre vonatkoz szablyok halmazai kztt
kell vlasztanunk, a !oa! objektumok hasznlata tnik sszerbbnek.
A !oa! objektumok gynevezett Ja-ekbl llnak, amelyek az egyes jellemzket (lebe-
gpontos rtk kirsakor hasznlt elvlaszt karakter (u!ua!_po!u(;, D.4.2), pnzrtk
beolvassakor hasznlt formtum (uou,pnu, D.4.3) stb.) szablyozzk. A Ja egy,
a !oa!..Ja osztlybl szrmaz osztly objektuma (D.3); leginkbb gy kpzelhetjk
el, hogy a !oa! Ja-ek trolja (D.2, D.3.1).
D.2. A locale osztly
A !oa! osztly s a hozz tartoz szolgltatsok a !oa!> fejllomnyban tallhatk:
!a:: :u..!oa! {
pn!!.
!a:: Ja, !o!!!uzo a:a!uazo :pn:, D
!a:: !u, !o! azouo::o :pn:, D
,puJ !u ago:,, Ja- :opo:o::::a :zo!g!o :pn:
Fggelkek s trgymutat 1178
:a! ou: ago:, a u,!g: : ug:a!o:::Jnggo
uou U,
o!!a I,
,p II,
uoua:, I2,
unu:! I,
!u I4,
u::ag: I5,
a!! o!!a ' ,p ' uoua:, ' unu:! ' !u ' u::ag:,
!oa!(; :ou(;, a g!o!!: !o! u:o!aa (D2I;
!oa!(ou: !oa!& .; :ou(;, . u:o!aa
.p!!! !oa!(ou: a:* p;, a p u:n !o! u:o!aa (D2I;
-!oa!(; :ou(;,
!oa!(ou: !oa!& ., ou: a:* p, ago:, ;, . u:o!aa, p!n:z p-!! Ja-
!oa!(ou: !oa!& ., ou: !oa!& ,, ago:, ;, . u:o!aa, p!n:z ,-!! Ja-
up!a !a:: 1a> !oa!(ou: !oa!& ., 1a* J;, . u:o!aa, p!n:z az J Ja
up!a !a:: 1a> !oa! ou!u(ou: !oa!& .;, *!: u:o!aa,
p!n:z az .-!! 1a
ou: !oa!& op:ao:(ou: !oa!& .; :ou(;,
oo! op:ao:(ou: !oa!&; ou:, !o!o o::za:ou!::a
oo! op:ao::(ou: !oa!&; ou:,
::!ug uau(; ou:, az auo !o! u: (D2I;
up!a !a:: , !a:: T:, !a:: > a:a:!uo o::za:ou!::a
az auo !o! :g::g:!
oo! op:ao:(;(ou: a:!_::!ug,T:,>&, ou: a:!_::!ug,T:,>&; ou:,
:a! !oa! g!oa!(ou: !oa!&;, a g!o!!: !o! !!::a : :!::za:: a :g!:!
:a! ou: !oa!& !a::!(;, a !a::z!n: -::!n: !o!
p:!:a.
:zo!:
},
A !oa!-ekre gy gondolhatunk, mint uap!u,Ja*>-ek felletre, vagyis valami olyasmi-
re, ami lehetv teszi, hogy egy !oa!..!u segtsgvel megtalljuk a megfelel objektumot,
amelynek osztlya a !oa!..Ja-bl szrmazik. A !oa! megvalstsa alatt az e gondolat
alapjn elksztett (hatkony) szerkezeteket rtjk. Az elrendezs ilyesmi lesz:
D. Helyi sajtossgok 1179
Itt a o!!aa:> s a unupnua:> a standard knyvtr Ja-jei (D.4). Mint mind-
egyik Ja, ezek is a !oa!..Ja-bl szrmaznak.
A !oa!-nek szabadon s olcsn msolhatnak kell lennie. Kvetkezskppen a !oa!-t
majdnem mindig gy valstjk meg, mint egy lert arra a szakostott uap!u,Ja*>-re,
amely a szolgltatsok legtbbjt tartalmazza. A lokl jellemzinek (a Ja-eknek) gyorsan
elrhetnek kell lennik, ezrt az egyedi cl uap!u,Ja*> a tmbkhz hasonl gyors
hozzfrst kell, hogy nyjtson. A !oa! jellemzinek elrse a n:_Ja1a>(!o; jel-
lssel trtnik (lsd D.3.1-et).
A standard knyvtr a Ja-ek gazdag vlasztkt nyjtja. A programoz ezeket logikai cso-
portokban kezelheti, mert a szabvnyos Ja-ek kategrikat alkotnak (pl. unu:! s
o!!a, D.4).
A programoz az egyes kategrikban lev jellemzket kicserlheti (D.4, D.4.2.1), de
nem adhat meg j kategrikat. A kategria fogalma csak a standard knyvtrbeli Ja-
ekre vonatkozik, nem terjeszthet ki a felhasznli jellemzkre. Ezrt nem szksges, hogy
egy Ja kategriba tartozzon s sok felhasznli Ja nem is tartozik ilyenbe.
A loklokat messze a leggyakrabban az adatfolyamok bemeneti s kimeneti mveletinl
hasznljuk, mg ha nem is tudunk rla. Minden !::au s o::au rendelkezik sajt lokl-
lal. Az adatfolyamok loklja a folyam ltrehozsnak pillanatban alaprtelmezs szerint
a globlis !oa! (D.2.1) lesz. A folyam lokljt az !un(; (megtlts) mvelettel lehet
belltani, a !oa! msolatt pedig a g!o(; fggvnnyel kaphatjuk meg (21.6.3).
Fggelkek s trgymutat 1180
u!ua!_po!u ( ;
:nuau ( ;
oupa: ( ;
a: ( ;
!oa!.
o!!aa:>.
unupnua:>.
D.2.1. Nevestett loklok
A loklok msik !oa!-bl s jellemzkbl hozhatk ltre. A legegyszerbb egy mr lte-
z !oa! lemsolsa:
!oa! !oU, az ::u,: g!o!!: !o! u:o!aa (D2;
!oa! !oI !oa!(;, az ::u,: g!o!!: !o! u:o!aa (D2;
!oa! !o2(;, a J!a:zu!o !a! !ou,u ::z:: !o!
u:o!aa
!oa! !o(;, a !o! u:o!aa
!oa! !o4 !oa!..!a::!(;, a !o! u:o!aa
!oa! !o5(POS1A;, az auo J!:zoo:u,z !a! uga:ozo
POS1A !o! u:o!aa
A !oa!(; jelentst a szabvny klasszikus C loklknt hatrozza meg; ebben a knyv-
ben vgig ezt a loklt hasznljuk. A tbbi !oa! neve a hasznlt C++-vltozattl fgg.
A !oa!(; a felhasznl ltal elnyben rszestett lokl, melyet a program vgrehajtsi
krnyezetben a nyelven kvli eszkzk lltanak be.
A legtbb opercis rendszer biztost valamilyen eszkzt a programok terleti belltsai-
nak megadsra. A belltsra legtbbszr akkor kerl sor, amikor a felhasznl elszr ta-
llkozik a rendszerrel. Egy olyan gpen pldul, ahol a rendszer alaprtelmezett nyelveknt
az argentin spanyolt adtk meg, a !oa!(; valsznleg a !oa!(:_R;-t jelenti.
Az egyik rendszerem gyors ellenrzse 51 megjegyezhet nvvel rendelkez loklt muta-
tott ki (pldul POS1A, u, u_UK, u_US, :, :_R, J:, ::, ua, p!, s !:o_335U_I). A POSIX
ltal ajnlott formtum: kisbets nyelvnv, amit nagybets orszgnv kvet (ez nem kte-
lez), valamint egy kdjelz (ez sem ktelez); pldul p_{P!. Ezek a nevek azonban
nem szabvnyostottak a klnbz platformok kztt. Egy msik rendszerben egyb
!oa! nevek mellett a kvetkezket talltam: g, n, n:, :, J:, :u, s ua. A C++ szabvny nem
adja meg az orszgok s nyelvek !oa!-jt, br az egyes platformokra ltezhetnek szabv-
nyok. Kvetkezskppen, ha a programoz nevestett loklokat akar hasznlni, a rendszer
dokumentcijra s tapasztalataira kell hagyatkoznia.
ltalban clszer elkerlni a loklneveket jelz karakterlncok programszvegbe gyaz-
st. A fjlnevek s rendszerllandk programban val szerepeltetse korltozza a prog-
ram hordozhatsgt, a programot j krnyezetbe beilleszteni kvn programoz pedig
gyakran arra knyszerl, hogy megkeresse ezeket az rtkeket, hogy mdosthassa azokat.
D. Helyi sajtossgok 1181
A loklnevek megemltse is hasonl kellemetlen kvetkezmnyekkel jr. Jobb, ha a lok-
lokat kivesszk a program vgrehajtsi krnyezetbl (pldul a !oa!(; felhasznls-
val) vagy a programra bzzuk, hogy a tapasztaltabb felhasznlktl a lokl meghatrozst
krje, mondjuk egy karakterlnc bekrsvel:
:o!u n::_:_!oa!(ou: ::!ug& n:!ou_::!ug;
{
on n:!ou_::!ug, p! Ha u: !o! ::u a:zu!u!, aua ug a u:
::!ug :,
!u >> :,
!oa!..g!oa!(!oa!(:_::(;;;, a J!a:zu!o !a! ugauo g!o!!: !o! !!::a
}
A kezd felhasznlk szmra ltalban jobb, ha lehetv tesszk, hogy listbl vlaszthassa-
nak. Az ezt kezel eljrsnak viszont tudnia kell, hol s hogyan trolja a rendszer a loklokat.
Ha a paramterknt megadott karakterlnc nem definilt !oa!-re hivatkozik, a konstruktor
:nu!u_::o: kivtelt vlt ki (14.10):
:o!u :_!o(!oa!& !o, ou: a:* uau;
:,
{
!o !oa!(uau;,
}
a (:nu!u_::o:; {
:: ` uau ` !o! uu uJ!u!!`u,
}
Ha a !oa! nevestett, a uau(; visszaadja annak nevt, ha nem, a ::!ug(*;-gal tr vissza.
A nv elssorban arra val, hogy hivatkozhassunk a vgrehajtsi krnyezetben trolt lok-
lokra, de a hibakeressben is segthet:
:o!u p:!u_!oa!_uau:(ou: !oa!& u,_!o;
{
on uau oJ n::u g!oa! !oa!. !oa!(;uau(; `u,
on uau oJ !a::! !oa!. !oa!..!a::!(;uau(; `u,
on uau oJ n::: p:J::u !oa!. !oa!(;uau(; `u,
on uau oJ u, !oa!. u,_!ouau(; `u,
}
Az alaprtelmezett ::!ug(*;-tl eltr, de azonos nev loklok sszehasonltskor egyen-
rtknek minslnek, az vagy : opertorokkal azonban az sszehasonlts kzvetle-
nebb mdon is elvgezhet.
Fggelkek s trgymutat 1182
A nvvel rendelkez !oa!-ek msolatai ugyanazt a nevet kapjk, mint az eredeti !oa! (ha
annak van neve), gy azonos nven tbb !oa! is szerepelhet. Ez logikus, mert a loklok
nem mdosthatk, gy ezen objektumok mindegyike a helyi sajtossgok ugyanazon hal-
mazt rja le.
A !oa!(!o,1oo,a; hvs a !o-hoz hasonl loklt hoz ltre, de annak jellemzit (a Ja-
eket) a !oa!(1oo; a kategrijbl veszi. Az eredmnyl kapott loklnak kizrlag ak-
kor lesz neve, ha a !o-nak is volt. A szabvny nem hatrozza meg pontosan, milyen nevet
kap az j !oa!, de feltehet, hogy klnbzni fog a !o-tl. A legegyszerbb, ha a nevet
a !o nevbl s a 1oo-bl ptjk fel. Pldul ha a !o neve u_UK, az j lokl neve
u_UK.1oo lesz.
Az j loklok elnevezsre vonatkoz szablyok a kvetkezkppen foglalhatk ssze:
A programoz az jonnan ltrehozott !oa!-ek neveknt nem adhat meg C stlus karak-
terlncot. A neveket a program vgrehajtsi krnyezete hatrozza meg vagy a !oa!
konstruktorok ptik fel azokat a nevek prostsbl.
D.2.1.1. j loklok ltrehozsa
j !oa! objektumot gy kszthetnk, hogy vesznk egy mr ltez !oa!-t s ehhez jel-
lemzket adunk vagy kicserlnk benne nhnyat. Az j !oa!-ek jellemzen egy mr l-
tez !oa! kiss eltr vltozatai:
D. Helyi sajtossgok 1183
Lokl Nv
!oa!(1oo; 1oo
!oa!(!o; !ouau(;
!oa!(!o,1oo,a; j nv, ha a !o-nak van neve; egybknt
::!ug(*;
!oa!(!o,!o2,a; j nv, ha a !o-nak s a !o2-nek is van
neve; egybknt ::!ug(*;
!oa!(!o,1a; ::!ug(*;
!oou!u(!o2; ::!ug(*;
:o!u J(ou: !oa!& !o, ou: M,_uou,_!o* u!o; D4I-u !::
M,_uou,_!o
{
!oa! !oI(!oa!(POS1A;, !o, !oa!..uoua:,;, !o-!! puzJo:unu-
!!uzo a:zu!aa
!oa! !o2 !oa!(!oa!..!a::!(;, u!o;, a !a::z!n:, p!n:z u!o
}
Itt !oI a POS1A lokl msolata, amit gy mdostottunk, hogy a !o pnzformtum-jellem-
zit hasznlja (D.4.3). Ehhez hasonlan, !o2 a lokl msolata, amely a M,_uou,_!o-t
hasznlja (D.4.3.1). Ha a 1a* paramter (itt a M,_uou,_!o) rtke U, az eredmnyl
kapott lokl egyszeren a !oa! paramter msolata lesz.
Ha a kvetkezt rjuk,
!oa!(ou: !oa!& ., 1a* J;,
az J paramternek egy meghatrozott Ja tpust kell jellnie. Egy egyszer Ja* nem ele-
gend:
:o!u g(ou: !oa!..Ja* u!oI, ou: M,_uou,_!o* u!o2;
{
!oa! !o !oa!(!oa!..!a::!(;, u!oI;, !a. a Ja :pn:a uu !:u:
!oa! !o4 !oa!(!oa!..!a::!(;, u!o2;, :uuu. a Ja :pn:a !:u:
}
Ennek az az oka, hogy a !oa! a 1a* paramter tpust hasznlja arra, hogy fordtsi id-
ben megllaptsa a Ja tpust. Pontosabban, a !oa! megvalstsa a jellemz azonost-
jt, a Ja..!u-t (D.3.3) hasznlja, hogy a jellemzt megtallja a loklban (D.3.1).
Jegyezzk meg, hogy a
up!a !a:: 1a> !oa!(ou: !oa!& ., 1a* J;,
konstruktor a nyelv ltal nyjtott egyetlen eljrs a programoz szmra, hogy Ja-eket
adhasson meg, melyeket egy !oa!-en keresztl hasznlni lehet. Az egyb loklokat a meg-
valst programozknak kell megadniuk, nevestett !oa!-ek formjban (D.2.1), melye-
ket a program vgrehajtsi krnyezetbl lehet megszerezni. Ha a programoz rti az erre
hasznlatos a fejlesztkrnyezettl fgg eljrst, a meglev loklok krt jakkal b-
vtheti (D.6[11,12]).
Fggelkek s trgymutat 1184
A loklok konstruktorainak halmazt gy terveztk, hogy minden jellemz tpusa meglla-
pthat legyen, vagy tpuslevezets tjn (a 1a sablonparamter tpusbl), vagy azrt,
mert egy msik loklbl szrmazik, amely ismerte a jellemz tpust. A ago:, paramter
megadsval a Ja-ek tpust kzvetett mdon is meghatrozhatjuk, hiszen a loklok isme-
rik a kategrikban lv jellemzk tpust. Ebbl kvetkezik, hogy a !oa! osztly nyomon
kvetheti a Ja-ek tpust, gy azokat klnsebb tbbletterhels nlkl mdosthatja is.
A lokl a Ja tpusok azonostsra a !oa!..!u tagtpust hasznlja (D.3).
Nha hasznos lehet olyan loklt ltrehozni, amely egy msik lokl msolata, de az egyik jel-
lemzje egy harmadik loklbl szrmazik. A ou!u(; sablon tagfggvny erre val:
:o!u J(ou: !oa!& !o, ou: !oa!& !o2;
{
!oa! !o !oou!u M,_uou,_!o >(!o2;,
}
Az eredmnyl kapott !o gy viselkedik, mint a !o, de a pnzformtumot a !o2-ben le-
v M,_uou,_!o (D.4.3.1) msolata alapjn lltja be. Ha a !o2 nem rendelkezik
a M,_uou,_!o-val, hogy tadhassa azt az j loklnak, a ou!u(; :nu!u_::o:-t
(14.10) vlt ki. A ou!u(; eredmnyeknt kapott lokl nem nevestett.
D.2.2. Loklok msolsa s sszehasonltsa
A loklok kezdeti vagy egyszer rtkadssal msolhatk:
:o!u :uap(!oa!& ., !oa!& ,; ng,auaz, u!u az :u..:uap(;
{
!oa! up .,
. ,,
, up,
}
A msolat az eredetivel egyenrtk, de fggetlen, nll objektum:
:o!u J(!oa!* u,_!oa!;
{
!oa! !o !oa!..!a::!(;, !o!
!J (!o : !oa!..!a::!(;; {
:: H!a a ug:a!o:::au. :::: a :z:o`u,
D. Helyi sajtossgok 1185
.!(I;,
}
!J (&!o : &!oa!..!a::!(;; on Nu ug!po. a :u n!ouozu`u,
!oa! !o2 !oa!(!o, u,_!oa!, !oa!..unu:!;,
!J (!o !o2; {
on a !a::!(; a:ou!o Ja-u !:o!`u,
}
}
Ha a u,_!oa! rendelkezik olyan jellemzvel, amely a !a::!(; lokl szabvnyos
unupnua:>-jtl eltren adja meg a szmok elvlaszt rsjeleit (u,_unupnua:>),
az eredmnyl kapott loklok a kvetkezkppen lesznek brzolhatk:
Fggelkek s trgymutat 1186
oupa: ( ;
a: ( ;
u!ua!_po!u ( ;
n::_:,uo! ( ;
u!ua!_po!u ( ;
n::_:,uo! ( ;
!o.
o!!aa:>.
unupnua:>.
u,_unupnua:>.
!o2.
A !oa! objektumok nem mdosthatk, mveleteik viszont lehetv teszik j loklok lt-
rehozst a mr meglevkbl. A ltrehozs utni mdosts tiltsa (a lokl nem vltoz-
kony, !uuna! termszete) alapvet fontossg a futsi idej hatkonysg rdekben,
ez teszi ugyanis lehetv a felhasznl szmra, hogy meghvja a Ja-ek virtulis fggv-
nyeit s trolja a visszaadott rtkeket. A bemeneti adatfolyamok pldul anlkl tudhatjk,
milyen karakter hasznlatos a tizedesvessz (pontosabban tizedespont) jelzsre, illetve
anlkl ismerhetik a :n brzolst, hogy minden egyes alkalommal meghvnk szm
beolvassakor a u!ua!_po!u(; fggvnyt vagy logikai rtk beolvassakor
a :nuau(;-et (D.4.2). Csak az !un(; meghvsa az adatfolyamra (21.6.3) okozhatja,
hogy ezek a hvsok klnbz rtkeket adjanak vissza.
D.2.3. A global() s classic() loklok
A programban rvnyben lev lokl msolatt a !oa!(; adja vissza, a !oa!..g!oa!(.; pe-
dig .-re lltja azt. Az rvnyes loklt gyakran globlis loklnak hvjk, utalva arra, hogy
valsznleg globlis (vagy statikus) objektum.
Az adatfolyamok ltrehozsukkor automatikusan feltltdnek (imbue; 21.1, 21.6.3)
a globlis lokllal, vagyis a !oa!(; msolatval, ami elszr mindig a szabvnyos C
!oa!..!a::!(;.
A !oa!..g!oa!(; statikus tagfggvny megengedi, hogy a programoz meghatrozza, me-
lyik lokl legyen globlis. Az elz msolatt a g!oa!(; fggvny adja vissza; ennek segt-
sgvel a felhasznl visszallthatja az eredeti globlis loklt:
:o!u J(ou: !oa!& u,_!o;
{
!J::au J!uI(:ou_uau;, J!uI J!o!: a g!o!!: !o!!a!
!oa!& o!u_g!oa! !oa!..g!oa!(u,_!o;, g!o!!: !o! !!::a
!J::au J!u2(:ou_o:_uau;, J!u2 J!o!: a u,_!o !o!!a!
!oa!..g!oa!(o!u_g!oa!;, a :g! g!o!!: !o! :!::za!!::a
}
Ha az . lokl rendelkezik nvvel, a !oa!..g!oa!(.; szintn a C globlis loklt lltja be. Eb-
bl kvetkezik, hogy egy vegyes (C s C++) programban egysgesen s kvetkezetesen ke-
zelhetjk a loklt, ha meghvjuk a C standard knyvtrnak valamelyik loklfggvnyt.
Ha az . loklnak nincs neve, akkor nem meghatrozhat, hogy a !oa!..g!oa!(.; befoly-
solja-e a C globlis loklt, vagyis a C++ programok nem kpesek megbzhatan (s hor-
dozhat mdon) tlltani a C loklt egy olyan loklra, amely nem a vgrehajtsi krnye-
D. Helyi sajtossgok 1187
zetbl val. Nincs szabvnyos md arra sem, hogy egy C program bellthassa a C++ glo-
blis loklt (kivve ha meghv egy C++ fggvnyt, ami ezt megteszi), ezrt a hibk elker-
lse rdekben a vegyes programokban nem clszer a g!oa!(;-tl eltr C globlis loklt
hasznlni.
A globlis lokl belltsa nincs hatssal a mr ltez I/O adatfolyamokra; azok ugyanazt
a loklt fogjk hasznlni, amivel eredetileg feltltdtek. A J!uI-re pldul nem hat a glob-
lis lokl mdostsa, de a J!u2-t a mvelet a u,_!o-kal tlti fel.
A globlis lokl mdostsval ugyanaz a problma, mint a globlis adatokat megvltozta-
t egyb eljrsokkal: lnyegben nem tudhat, mire van hatssal a vltoztats. Ezrt a leg-
jobb, ha a g!oa!(;-t a lehet legkevesebbszer hasznljuk s a mdostst olyan kdrszle-
tekre korltozzuk, ahol annak hatsa pontosan nyomon kvethet. Szerencsre ezt segti
az a lehetsg, hogy az adatfolyamokat meghatrozott loklokkal tlthetjk meg (imbue,
21.6.3). Azrt vigyzzunk: ha a programban elszrva szmos explicit !oa!- s Ja-keze-
l kd tallhat, a program nehezen lesz fenntarthat s mdosthat.
D.2.4. Karakterlncok sszehasonltsa
A loklokat tbbnyire arra hasznljuk, hogy sszehasonltsunk kt karakterlncot egy
!oa! alapjn. Ezt a mveletet maga a !oa! nyjtja, a felhasznlknak nem kell sajt ssze-
hasonlt eljrst rniuk a o!!a jellemzbl (D.4.1). Az eljrs a lokl op:ao:(; (; ssze-
hasonlt fggvnye, gy kzvetlenl hasznlhat prediktumknt (18.4.2):
:o!u J(:o:::!ug>& :, ou: !oa!& u,_!oa!;
{
:o:(:g!u(;, :uu(;;, :uuz: a g!o!!: !o! :z:!u
:o:(:g!u(;, :uu(;, u,_!oa!;, :uuz: a u,_!oa! :za!,a! :z:!u
}
Alaprtelmezs szerint a standard knyvtrbeli :o:(; a mveletet alkalmazza a karakte-
rek szmrtkre, hogy eldntse a rendezsi sorrendet (18.7, 18.6.3.1).
Jegyezzk meg, hogy a loklok a:!_::!ug-eket hasonltanak ssze, nem C stlusakat.
Fggelkek s trgymutat 1188
D.3. Jellemzk
A jellemzk (Ja-ek) a lokl Ja tagosztlybl szrmaztatott osztlyok objektumai:
!a:: :u..!oa!..Ja {
p:ou.
.p!!! Ja(:!z_ : U;, :U. a !o! :za!,ozza a Ja !a:au
:!:na! -Ja(;, J!g,!u. :u u::no:
p:!:a.
Ja(ou: Ja&;, uu uga:ozo
:o!u op:ao:(ou: Ja&;, uu uga:ozo
:zo!:
},
A msol mveletek privt tagok s szndkosan nincsenek definilva, hogy a msolst
megakadlyozzk (11.2.2).
A Ja osztly bzisosztly szerepet tlt be, nyilvnos fggvnye nincs. Konstruktora v-
dett, hogy megakadlyozza az egyszer Ja objektumok ltrehozst, destruktora pedig
virtulis, hogy biztostsa a szrmazott osztlybeli objektumok megfelel megsemmistst.
A jellemzk kezelst a loklok elvileg mutatkon keresztl vgzik. A Ja
konstruktornak U rtk paramtere azt jelenti, hogy a loklnak trlnie kell az adott jel-
lemzt, ha mr nincs r hivatkozs. Ezzel szemben a nem nulla konstruktor-paramter azt
biztostja, hogy a !oa! sohasem trli a jellemzt. Ez az a ritka eset, amikor a Ja lettar-
tamt a programoz kzvetlenl, nem a loklon keresztl szablyozza.
A o!!a_,uaua:> szabvnyos Ja tpus objektumokat pldul gy hozhatjuk lt-
re (D.4.1.1):
:o!u J(ou: ::!ug& :I, ou: ::!ug& :2;
{
:zo:o: :. a U (a!ap:!uz; pa:au: az !z!,
og, a !o! J!! a J!:zuo!::
o!!aa:>* p uu o!!a_,uaua:>(p!;,
!oa! !o(!oa!(;, p;,
:!a :. a pa:au: : I, a J!a:zu!o J!! a J!:zuo!::
o!!aa:>* uu o!!a_,uaua:>(g,I;,
o!!a_,uaua:> ngI(:u;, !a. !o!!: :!ozo uu ! J!:zuo!u!
o!!a_,uaua:> ng2(uo,I;, !a. !o!!: :!ozo uu ! J!:zuo!u!
D. Helyi sajtossgok 1189
uu o:o!o. a o!!a_,uaua:> u::no:a :u
u!u: u! p, u: a !o! !uz! *p J!:zuo!:
}
Azaz a szabvnyos Ja-ek a lokl ltal kezelt bzisosztlyknt hasznosak, ritkn kell ms
mdon kezelnnk azokat.
A _,uau(; vgzds jellemzk a vgrehajtsi krnyezetben tallhat nevestett lokl
Ja-jei (D.2.1).
Minden Ja-nek rendelkeznie kell azonostval (!u), hogy a loklban a a:_Ja(; s
n:_Ja(; fggvnyekkel megtallhat legyen (D.3.1):
!a:: :u..!oa!..!u {
pn!!.
!u(;,
p:!:a.
!u(ou: !u&;, uu uJ!u!!
:o!u op:ao:(ou: !u&;, uu uJ!u!!
:zo!:
},
A msol mveletek privtok s nincsenek kifejtve, hogy a msolst megakadlyozzk
(11.2.2).
Az azonost arra val, hogy a jellemzk szmra j felletet ad osztlyokban (pldul
lsd D.4.1-et) !u tpus statikus tagokat hozhassunk ltre. A loklok eljrsai az !u-t hasz-
nljk a Ja-ek azonostsra (D.2, D.3.1). Az azonostk tbbnyire egy Ja-ekre hivat-
koz mutatkbl ll vektor indexrtkei (vagyis uap!u,Ja*>, ami igen hatkony).
A (szrmaztatott) jellemzket meghatroz adatokat a szrmaztatott osztly rja le, nem ma-
ga a Ja bzisosztly. Ebbl kvetkezik, hogy a programoz tetszleges mennyisg ada-
tot hasznlhat a Ja fogalmnak brzolsra s korltozs nlkl mdosthatja azokat.
Jegyezzk meg, hogy a felhasznli Ja-ek minden fggvnyt ou: tagknt kell megha-
trozni, mert a Ja-eknek llandnak kell lennik (D.2.2).
Fggelkek s trgymutat 1190
D.3.1. Jellemzk elrse a loklokban
A loklok Ja-jei a n:_Ja sablon fggvnyen keresztl rhetk el s a a:_Ja sab-
lon fggvnnyel krdezhetjk le, hogy a lokl rendelkezik-e egy adott jellemzvel:
up!a !a:: 1a> oo! a:_Ja(ou: !oa!&; :ou(;,
up!a !a:: 1a> ou: 1a& n:_Ja(ou: !oa!&;, au_a: !:! :!a
!
Ezekre a fggvnyekre gy kell gondolnunk, mintha azok !oa! paramterkben keresnk
1a sablonparamterket. Ms megkzeltsben a n:_Ja egyfajta tpusknyszerts
(cast), egy lokl konvertlsa egy meghatrozott jellemzre. Ez azrt lehetsges, mert
a !oa! objektumok egy adott tpus Ja-bl csak egy pldnyt tartalmazhatnak:
:o!u J(ou: !oa!& u,_!oa!;
{
a: n:_Ja unupnua:> >(u,_!oa!;u!ua!_po!u(; a :za:u,o:
Ja a:zu!aa
!J (a:_JaEu:,p>(u,_!oa!;; { a:a!uaz- a u,_!oa! Eu:,p Ja-.
ou: Eu:,p& J n:_JaEu:,p>(u,_!oa!;, az Eu:,p Ja !u,::
a u,_!oa!-o!
ou: :,po Jg_:,po(;, az Eu:,p Ja a:zu!aa
}
}
Jegyezzk meg, hogy a n:_Ja egy konstans Ja-re val referencit ad vissza, gy az
eredmnyt nem adhatjuk rtkl egy nem konstans vltoznak. Ez azrt logikus, mert a jel-
lemzknek elvileg nem mdosthatknak kell lennik s csak ou: tagokat tartalmazhatnak.
Ha meghvjuk a n:_JaA>(!o; fggvnyt s !o nem rendelkezik az A jellemzvel,
a n:_Ja(; au_a: kivtelt vlt ki (14.10). A szabvnyos Ja-ek garantltan hozzfr-
hetek minden !oa! szmra (D.4), gy az esetkben nem kell a a:_Ja-et hasznl-
nunk, ezekre a n:_Ja nem fog au_a: kivtelt kivltani.
Hogyan lehetne a n:_Ja s a:_Ja fggvnyeket megvalstani? Emlkezznk, hogy
egy loklra gy gondolhatunk, mintha uap!u,Ja*> lenne (D.2). Ha a 1a sablonpa-
ramterknt adott egy Ja tpus, a a:_Ja vagy n:_Ja a 1a..!u-re hivatkozhat s
ezt hasznlhatja a megfelel jellemz megkeressre. A a:_Ja s n:_Ja nagyon egy-
szer vltozata gy nzhetne ki:
D. Helyi sajtossgok 1191
!-ug:a!o:::. pz!n g,, og, a !o! :uu!z! g, Ja_uap-u u:z
uap!u,Ja*>-!
up!a !a:: 1a> oo! a:_Ja(ou: !oa!& !o; :ou(;
{
ou: !oa!..Ja* J !oJa_uap/1a..!u],
:n:u J . :n . Ja!:,
}
up!a !a:: 1a> ou: 1a& n:_Ja(ou: !oa!& !o;
{
ou: !oa!..Ja* J !oJa_uap/1a..!u],
!J (J; :n:u :a!_a:ou: 1a&>(*J;,
:ou au_a:(;,
}
A Ja..!u hasznlatt gy is tekinthetjk, mint a fordtsi idej tbbalaksg (parametrikus
polimorfizmus) egy formjt. A u,uau!_a: a n:_Ja-hez hasonl eredmnyt adna, de
az utbbi sokkal hatkonyabb, mert kevsb ltalnos.
Az !u valjban inkbb egy felletet s viselkedst azonost, mint osztlyt. Azaz ha kt Ja-
osztlynak pontosan ugyanaz a fellete s (a !oa! szempontjbl) ugyanaz a szerepk,
akkor ugyanaz az !u kell, hogy azonostsa ket. A o!!aa:> s
a o!!a_,uaua:> pldul felcserlhet egy loklban, gy mindkettt
a o!!aa:>..!u azonostja (D.4.1).
Ha egy jellemznek j felletet adunk mint az J(;-ben az Eu:,p-nek , definilnunk kell
szmra az azonostt (lsd D.3.2-t s D.4.1-et).
D.3.2. Egyszer felhasznli facet-ek
A standard knyvtr a kulturlis eltrsek leglnyegesebb terleteihez mint a karakter-
kszletek kezelse s a szmok be- s kivitele szabvnyos Ja-eket nyjt. Ahhoz, hogy
az ltaluk nyjtott szolgltatsokat a szles krben hasznlatos tpusok bonyolultsgtl s
a velk jr hatkonysgi problmktl elklntve vizsglhassuk, hadd mutassak be el-
szr egy egyszer felhasznli tpusra vonatkoz Ja-et:
unu Sa:ou { a:a:z, u,:, o:z, ! }, ::zao
Fggelkek s trgymutat 1192
Ez volt a legegyszerbb felhasznli tpus, ami ppen eszembe jutott. Az itt felvzolt I/O kis
mdostsokkal a legtbb egyszer felhasznli tpus esetben felhasznlhat.
!a:: Sa:ou_!o . pn!! !oa!..Ja {
pn!!.
Sa:ou_!o(!u ! U; . !oa!..Ja(!; { }
-Sa:ou_!o(; { } !o: :z! a Sa:ou_!o onuo J!:zuo!: (D;
. :zo!:a a:a:!uu
:!:na! ou: ::!ug& o_::(Sa:ou .; ou: U,
az : a:a:!uua ugJ!!o ::za !!,z: .-.
:!:na! oo! J:ou_::(ou: ::!ug& :, Sa:ou& .; ou: U,
:a! !oa!..!u !u, Ja-azouo::o onu (D2, D, DI;
},
!oa!..!u Sa:ou_!o..!u, az azouo::o onu uga:oz:a
Az egyszersg kedvrt a Ja csak a a: tpust hasznl megvalstsokra korltozdik.
A Sa:ou_!o osztly ltalnos, elvont felletet nyjt minden Sa:ou_!o Ja szmra.
Ha a Sa:ou be- s kimenett egy adott loklra szeretnnk definilni, a Sa:ou_!o-bl szr-
maztatunk egy osztlyt, amelyben megfelelen kifejtjk a o_::(; s J:ou_::(; fggvnye-
ket.
A Sa:ou rtkt knny kirni. Ha az adatfolyam rendelkezik Sa:ou_!o jellemzvel, azt
hasznlva az rtket karakterlncc alakthatjuk, ha nem, kirhatjuk a Sa:ou egsz rtkt:
o::au& op:ao:(o::au& :, Sa:ou .;
{
ou: !oa!& !o :g!o(;, az auaJo!,au !o!ua !u,:: (2I7I;
!J (a:_JaSa:ou_!o>(!o;; :n:u : n:_JaSa:ou_!o>(!o;o_::(.;,
:n:u : !u(.;,
}
szrevehetjk, hogy a mveletet gy definiltuk, hogy ms tpusokra hvtuk meg a -
t. Ennek szmos elnye van: egyszerbb a -t hasznlnunk, mint a kimeneti adatfolyam
tmeneti traihoz kzvetlenl hozzfrnnk, a << mveletet kifejezetten a loklhoz igazt-
hatjuk s a mvelet hibakezelst is biztost. A szabvnyos Ja-ek a legnagyobb hatkony-
sg s rugalmassg elrse rdekben tbbnyire kzvetlenl az adatfolyam tmeneti trt
kezelik (D.4.2.2, D.4.2.3), de sok felhasznli tpus esetben nincs szksg arra, hogy
a ::aunJ absztrakcis szintjre sllyedjnk.
D. Helyi sajtossgok 1193
Ahogy lenni szokott, a bemenet kezelse nmileg bonyolultabb, mint a kimenet:
!::au& op:ao:>>(!::au& :, Sa:ou& .;
{
ou: !oa!& !o :g!o(;, az auaJo!,au !o!ua !u,:: (2I7I;
!J (a:_JaSa:ou_!o>(!o;; { a :zo:g: :zo!: o!:a::a
ou: Sa:ou_!o& J n:_JaSa:ou_!o>(!o;,
::!ug nJ,
!J (:(:>>nJ && JJ:ou_::(nJ,.;;; :::a(!o:_a:..Ja!!!;,
:n:u :,
}
!u !, a :zu:zo!: o!:a::a
: >> !,
. Sa:ou(!;,
:n:u :,
}
A hibakezels egyszer, a beptett tpusok hibakezelsnek stlust kveti. Azaz, ha a be-
men karakterlnc nem a vlasztott lokl valamelyik Sa:ou-jt jelli, az adatfolyam hibs
(Ja!!n:) llapotba kerl. Ha a kivtelek megengedettek, !o:_a:..Ja!!n: kivtel kivlts-
ra kerlhet sor (21.3.6).
Vegynk egy egyszer tesztprogramot:
!u ua!u(; g,:z:n :z
{
Sa:ou .,
az a!ap:!uz !o! a:zu!aa (u!u: Sa:ou_!o Ja;,
g:z :n 1O- :uuu,z.
!u >> .,
on . uu!,
!oa! !o(!oa!(;, uu US_:a:ou_!o;,
on!un(!o;, Sa:ou_!o Ja-! :uu!zo !o! a:zu!aa
!u!un(!o;, Sa:ou_!o Ja-! :uu!zo !o! a:zu!aa
!u >> .,
on . uu!,
}
A
2
:nuu:
Fggelkek s trgymutat 1194
bemenetre a program vlasza:
2
:nuu:
Ennek elrshez definilnunk kell a US_:a:ou_!o osztlyt, amelyben megadjuk az vszak-
ok karakterlnc-brzolst s fellrjuk a Sa:ou_!o azon fggvnyeit, amelyek a karakter-
lncokat a felsorolt elemekre alaktjk:
!a:: US_:a:ou_!o . pn!! Sa:ou_!o {
:a! ou: ::!ug :a:ou:/],
pn!!.
ou: ::!ug& o_::(Sa:ou; ou:,
oo! J:ou_::(ou: ::!ug&, Sa:ou&; ou:,
J!g,!u. u!u: US_:a:ou_!o..!u
},
ou: ::!ug US_:a:ou_!o..:a:ou:/] { :p:!ug, :nuu:, Ja!!, u!u: },
ou: ::!ug& US_:a:ou_!o..o_::(Sa:ou .; ou:
{
!J (.:p:!ug '' u!u:.; {
:a! ou: ::!ug :: N!u: !!,u ::za,
:n:u ::,
}
:n:u :a:ou:/.],
}
oo! US_:a:ou_!o..J:ou_::(ou: ::!ug& :, Sa:ou& .; ou:
{
ou: ::!ug* g &:a:ou:/:p:!ug],
ou: ::!ug* uu &:a:ou:/u!u:]-I,
ou: ::!ug* p J!uu(g,uu,:;, 3I, I352
!J (puu; :n:u Ja!:,
. Sa:ou(p-g;,
:n:u :n,
}
Vegyk szre, hogy mivel a US_:a:ou_!o csupn a Sa:ou_!o fellet megvalstsa, nem
adunk meg azonostt a US_:a:ou_!o szmra. St, ha a US_:a:ou_!o-t Sa:ou_!o-knt
akarjuk hasznlni, nem is szabad ilyet tennnk. A loklok mveletei (pldul a a:_Ja,
D.3.1) arra tmaszkodnak, hogy az azonos fogalmakat brzol Ja-eket ugyanaz az !u
azonostja (D.3).
D. Helyi sajtossgok 1195
A megvalstssal kapcsolatos egyetlen rdekes krds az, hogy mit kell tenni, ha rvny-
telen Sa:ou kirst krik? Termszetesen ennek nem lenne szabad megtrtnnie. Az egy-
szer felhasznli tpusoknl azonban nem ritka, hogy rvnytelen rtket tallunk, gy
szmtsba kell vennnk ezt a lehetsget is. Kivlthatnnk egy kivtelt, de miutn olyan
egyszer kimenettel foglalkozunk, amelyet emberek fognak olvasni, hasznos, ha a tartom-
nyon kvli rtkeket az rtktartomnyon kvli szveg is jelzi. A bemenetnl itt a kiv-
telkezels a >> mveletre hrul, mg a kimenet esetben ezt a Ja o_::(; fggvnye vg-
zi (hogy bemutathassuk a lehetsgeket). Valdi programoknl a Ja fggvnyei a be- s
kimeneti hibk kezelsvel egyarnt foglalkoznak, vagy csak jelentik a hibkat, a s >>
mveletekre bzva azok kezelst.
A Sa:ou_!o ezen vltozata arra tmaszkodott, hogy a szrmaztatott osztlyok adjk meg
a loklra jellemz karakterlncokat. Egy msik megolds, hogy a Sa:ou_!o maga szerzi
meg ezeket egy, a loklhoz kapcsold adattrbl (lsd D.4.7). Gyakorlatknt hagytuk an-
nak kidolgozst, hogy egyetlen Sa:ou_!o osztlyunk van, amelynek az vszakokat jelz
karakterlncok a konstruktor paramtereknt addnak t (D.6[2]).
D.3.3. A loklok s jellemzk hasznlata
A loklok elsdlegesen a standard knyvtron bell, az I/O adatfolyamokban hasznlato-
sak, de a !oa! a helyi sajtossgok brzolsnak ennl ltalnosabb eszkze. A u::ag:
(D.4.7) pldul olyan Ja, amelynek semmi kze a be- s kimeneti adatfolyamokhoz.
Az !o::auknyvtr esetleges bvtsei, st, a nem adatfolyamokkal dolgoz be- s kime-
neti eszkzk is kihasznlhatjk a loklok adta lehetsgeket, a felhasznl pedig a !oa!
objektumok segtsgvel tetszleges mdon rendezheti a helyi sajtossgokat.
A loklokon s jellemzkn alapul eljrsok ltalnossga rvn a felhasznli Ja-ek
adta lehetsgek korltlanok. A dtumok, idznk, telefonszmok, trsadalombiztostsi
szmok (szemlyi szmok), gyrtsi szmok, hmrskletek, ltalnos (mrtkegysg, r-
tk) prok, irnytszmok, ruhamretek, s ISBN szmok mind megadhatk Ja-knt.
Mint minden ers szolgltatssal, a Ja-ekkel is vatosan kell bnni. Az, hogy valamit le-
het jellemzknt brzolni, mg nem jelenti azt, hogy ez a legjobb megolds. A kulturlis
eltrsek brzolsnak kivlasztsakor a kulcskrds mint mindig az, hogy milyen ne-
hz a kd megrsa, mennyire knny a kapott kdot olvasni, valamint hogy hogyan befo-
lysoljk a dntsek a kapott program fenntarthatsgt, illetve az I/O mveletek id- s
trbeli hatkonysgt.
Fggelkek s trgymutat 1196
D.4. Szabvnyos facet-ek
A standard knyvtr !oa!> fejllomnya a kvetkez Ja-eket nyjtja a !a::!(; loklhoz:
A tblzatban a helyn a: vagy ua:_ tpus szerepelhet. Ha a felhasznlnak arra
van szksge, hogy a szabvnyos I/O msfajta A karaktertpust kezeljen, a megfelel Ja-
eket meg kell adnia az A szmra. A ou:A,a:,u:a_> (D.4.6) pldul szksges
lehet az A s a: tpusok kztti talaktsokhoz. Az u:a_ tpus arra val, hogy egy
tbbjtos karakterbrzols lptetsi llapotait jellje (D.4.6); definicija a ua:> s
a ua:> fejllomnyokban tallhat. Tetszleges A karaktertpus esetben az
u:a_-nek a a:_:a!:A>..:a_,p felel meg.
D. Helyi sajtossgok 1197
Szabvnyos facet-ek (a classic() loklban)
D.4.1 o!!a Karakterlncok o!!a>
sszehasonltsa
D.4.2 unu:! Szmok be- s kivitele unupnu>
unu_g>
unu_pn>
D.4.3 uoua:, Pnz I/O uou,pnu>
uou,pnu,:n>
uou,_g>
uou,_pn>
D.4.4 !u Id I/O !u_g>
!u_pn>
D.4.5 ,p Karakterek osztlyozsa ,p>
ou:,a:,u:a_>
D.4.7 u::ag: zenet-visszakeress u::ag:>
Kategria Rendeltets Facet-ek
A standard knyvtr tovbbi Ja-jei a !oa!> fejllomnyban a kvetkezk:
A tblzatban szerepl jellemzk pldnyostsakor a a: vagy ua:_ lehet; a br-
milyen karaktertpus (20.1), az 1u:ua!oua! rtke :n vagy Ja!:, ahol a :n azt jelenti,
hogy a valuta-szimblum ngykarakteres nemzetkzi brzolst hasznljuk (D.4.3.1).
Az u:a_ tpus a tbbjtos karakter-brzolsok lptetsi llapotait jelli (D.4.6), meg-
hatrozsa a ua:> s a ua:> fejllomnyokban tallhat.
Az 1u s az On bemeneti s kimeneti bejrk (itertorok, 19.1, 19.2.1). Ha a _pn s _g
jellemzket elltjuk ezekkel a sablonparamterekkel, olyan Ja-eket hozhatunk ltre,
amelyek nem szabvnyos tmeneti trakhoz frnek hozz (D.4.2.2). Az !o::au-ek tme-
neti trai (pufferei) adatfolyam tmeneti trak, gy bejrik o::aunJ_!:ao:-ok
(19.2.6.1, D.4.2.2), vagyis a hibakezelshez rendelkezsnkre ll a Ja!!u(; fggvny.
Az 1_,uau az 1 Ja-bl szrmazik; ugyanazt a felletet nyjtja mint az 1, de hozzad
egy konstruktort, amelynek egy loklt megnevez karakterlnc paramtere van (lsd
D.4.1-et). Az 1_,uau(u:; jelentse ugyanaz, mint az 1 !oa!(u:; szerkezet. Az el-
gondols az, hogy a program vgrehajtsi krnyezetben egy nevestett loklbl (D.2.1)
kivesszk a szabvnyos Ja egy adott vltozatt:
Fggelkek s trgymutat 1198
Szabvnyos facet-ek
Kategria Rendeltets Facet-ek
D.4.1 o!!a Karakterlncok o!!a_,uau>
sszehasonltsa
D.4.2 unu:! Szmok be- s kivitele unupnu_,uau>
unu_g,1u>
unu_pn,On>
D.4.3 uoua:, Pnz I/O uou,pnu_,uau,1u:ua!oua!>
uou,_g,1u>
uou,_pn,On>
D.4.4 !u Id I/O !u_pn_,uau>
D.4.5 ,p Karakterek osztlyozsa ,p_,uau>
D.4.7 u::ag: zenet-visszakeress u::ag:_,uau>
:o!u J(:o:::!ug>& :, ou: !oa!& !o;
{
!oa! uI(!o, uu o!!a_,uaua:>(ua;;, uu a:a:!u-o::za:ou!::
a:zu!aa
!oa! u(uI, uu ,p_,uaua:>(ua;;, uu a:a:o:z!,oz: a:zu!aa
:o:(:g!u(;, :uu(;, u;,
}
Az j u lokl dn stlus karakterlncokat fog hasznlni, de megtartja a szmokra vonat-
koz alaprtelmezett szablyokat. Mivel a Ja msodik paramtere alaprtelmezs szerint
U, a uu mvelettel ltrehozott Ja lettartamt a lokl fogja kezelni (D.3).
A karakterlnc paramterekkel rendelkez !oa!-konstruktorokhoz hasonlan a _,uau-
konstruktorok is hozzfrnek a program vgrehajtsi krnyezethez. Ebbl az kvetkezik,
hogy nagyon lassak azokhoz a konstruktorokhoz kpest, amelyeknek nem kell a krnye-
zethez fordulniuk informcirt. Majdnem mindig gyorsabb, ha ltrehozunk egy loklt s
azutn frnk hozz annak jellemzihez, mintha _,uau Ja-eket hasznlnnk tbb he-
lyen a programban. Ezrt j tlet, ha a Ja-et egyszer olvassuk be a krnyezetbl, majd
ksbb mindig a memriban lv msolatt hasznljuk:
!oa! u(ua;, a uu !o! o!:a::a (!:: o::z: Ja-; g,:z:,
uau a u !o! : !!uzo!u a:zu!aa !gu, :z:!u
:o!u J(:o:::!ug>& :, ou: !oa!& !o;
{
ou: o!!aa:>& o! n:_Ja o!!aa:> >(u;,
ou: o!!aa:>& ,p n:_Ja ,pa:> >(u;,
!oa! uI(!o,o!;, uu a:a:!u-o::za:ou!:: a:zu!aa
!oa! u2(uI,,p;, uu a:a:o:z!,oz: : a:a:!u-
o::za:ou!:: a:zu!aa
:o:(:g!u(;, :uu(;, u2;,
}
A kategrik egyszerbb teszik a loklok szabvnyos Ja-jeinek kezelst. Pldul ha
adott a u lokl, ltrehozhatunk belle egy msikat, amely a dn nyelv szablyainak meg-
felelen (ez az angolhoz kpest hrom tovbbi magnhangzt jelent) olvas be s hasonlt
ssze karakterlncokat, de megtartja a C++-ban hasznlatos szmformtumot:
!oa! u_n:(!oa!..!a::!(;, u, o!!a',p;, uu n, au:!a! :zuo
D. Helyi sajtossgok 1199
Az egyes szabvnyos Ja-ek bemutatsnl tovbbi pldkat nznk meg a jellemzk
hasznlatra. A o!!a (D.4.1) trgyalsakor pldul a Ja-ek sok kzs szerkezetbeli tu-
lajdonsga elkerl.
Jegyezzk meg, hogy a szabvnyos Ja-ek gyakran fggnek egymstl. A unu_pn pl-
dul a unupnu-ra tmaszkodik. Csak ha az egyes jellemzket mr rszletesen ismerjk,
akkor lehetnk kpesek azokat sikeresen egytt hasznlni, egyeztetni vagy j vltozataikat
elkszteni. Ms szavakkal, a 21.7 pontban emltett egyszer mveleteken tl a loklok
nem arra valk, hogy a kezdk kzvetlenl hasznljk azokat.
A jellemzk megtervezse gyakran nagyon krlmnyes. Ennek oka rszben az, hogy a jel-
lemzk nem rendszerezhet helyi sajtossgokat kell, hogy tkrzzenek, melyekre
a knyvtr tervezje nincs befolyssal; msrszt pedig az, hogy a C++ standard knyvtr-
beli eszkzeinek nagyrszt sszeegyeztethetnek kell maradniuk azzal, amit a C standard
knyvtra s az egyes platformok szabvnyai nyjtanak. A POSIX pldul olyan eszkzk-
kel tmogatja a loklok hasznlatt, melyeket a knyvtrak tervezi nem szabad, hogy fi-
gyelmen kvl hagyjanak.
Msfell a loklok s jellemzk ltal nyjtott szerkezet nagyon ltalnos s rugalmas.
A Ja-ek brmilyen adatot trolhatnak s azokon brmilyen mveletet vgezhetnek. Ha
az j Ja viselkedst a szablyok nem korltozzk tlsgosan, szerkezete egyszer s
tiszta lehet (D.3.2).
D.4.1. Karakterlncok sszehasonltsa
A szabvnyos o!!a jellemz tpus karakterekbl ll tmbk sszehasonltst teszi
lehetv:
up!a !a:: >
!a:: :u..o!!a . pn!! !oa!..Ja {
pn!!.
,puJ a:_,p,
,puJ a:!_::!ug> ::!ug_,p,
.p!!! o!!a(:!z_ : U;,
!u oupa:(ou: * , ou: * , ou: * 2, ou: * 2; ou:
{ :n:u uo_oupa:(,,2,2;, }
!oug a:(ou: * , ou: * ; ou: { :n:u uo_a:(,;, }
::!ug_,p :au:Jo:u(ou: * , ou: * ; ou: { :n:u uo_:au:Jo:u(,;, }
Fggelkek s trgymutat 1200
:a! !oa!..!u !u, Ja-azouo::o onu (D2, D, DI;
p:ou.
-o!!a(;, J!g,!u. :u u::no:
:!:na! !u uo_oupa:(ou: * , ou: * , ou: * 2, ou: * 2; ou:,
:!:na! ::!ug_,p uo_:au:Jo:u(ou: * , ou: * ; ou:,
:!:na! !oug uo_a:(ou: * , ou: * ; ou:,
},
A tbbi Ja-hez hasonlan a o!!a is nyilvnos mdon szrmazik a Ja osztlybl s
olyan konstruktorral rendelkezik, amelynek egyetlen paramtere azt mondja meg, hogy
a !oa! osztly vezrli-e a jellemz lettartamt (D.3).
Jegyezzk meg, hogy a destruktor vdett (protected). A o!!a nem kzvetlen hasznlatra
val, inkbb arra szntk, hogy minden (szrmaztatott) sszehasonlt osztly alapja legyen
s a !oa! kezelje (D.3). A rendszerfejlesztknek s a knyvtrak ksztinek a karakter-
lncokat sszehasonlt Ja-eket gy kell megrniuk, hogy a o!!a nyjtotta felleten ke-
resztl lehessen hasznlni azokat.
Az alapvet karakterlnc-sszehasonltst a oupa:(; fggvny vgzi, az adott o!!a-re
vonatkoz szablyok szerint; I-et ad vissza, ha az els karakterlnc tbb karakterbl ll,
mint a msodik, U-t, ha a karakterlncok megegyeznek, s -I-et, ha a msodik karakter-
lnc nagyobb, mint az els:
:o!u J(ou: ::!ug& :I, ou: ::!ug& :2, o!!aa:>& up;
{
ou: a:* :I :Iuaa(;, u!:! a oupa:(; un:! a:/] ouou uo!goz!
ou: a:* :2 :2uaa(;,
:u! ( upoupa:(:I,:I-:I:!z(;, :2,:2-:2:!z(;; ;
{
a: U. a up :z:!u azouo: a:a:!uo
:a,
a: -I. :I :2
:a,
a: I. :I > :2
:a,
}
}
D. Helyi sajtossgok 1201
Vegyk szre, hogy a o!!a tagfggvnyek tpus elemekbl ll tmbket hasonlta-
nak ssze, nem a:!_::!ug-eket vagy nulla vgzds C stlus karakterlncokat, vagyis
a U szmrtk kznsges karakternek minsl, nem vgzdsnek. A oupa:(; ab-
ban is klnbzik a ::up(;-tl, hogy pontosan a -I, U, I rtkeket adja vissza, nem egy-
szeren U-t s (tetszleges) pozitv s negatv rtkeket (20.4.1).
A standard knyvtrbeli ::!ug nem fgg a lokloktl, azaz a karakterlncok sszehasonl-
tsa az adott nyelvi vltozat karakterkszlete alapjn trtnik (C.2). Ezenkvl a szabv-
nyos ::!ug nem biztost kzvetlen mdot arra, hogy meghatrozzuk az sszehasonltsi fel-
ttelt (20. fejezet). A lokltl fgg sszehasonltshoz a o!!a kategria oupa:(;
fggvnyt hasznlhatjuk. Mg knyelmesebb, ha a fggvnyt a lokl op:ao:(; operto-
rn keresztl, kzvetett mdon hvjuk meg (D.2.4):
:o!u J(ou: ::!ug& :I, ou: ::!ug& :2, ou: a:* u;
{
oo! :I :2, o::za:ou!:: a ug:a!o::: a:a::z!u :! :z:!u
ou: a:* :I :Iuaa(;, u!:! a oupa:(; un:! a:/] ouou uo!goz!
ou: a:* :2 :2uaa(;,
,puJ o!!aa:> o!,
ou: o!& g!o n:_Jao!>(!oa!(;;, az ::u,: g!o!!: !o!o!
!u !U g!ooupa:(:I,:I-:I:!z(;,:2,:2-:2:!z(;;,
ou: o!& u,_o!! n:_Jao!>(!oa!(;;, az !ou,u ::z:: !o!o!
!u !I u,_o!!oupa:(:I,:I-:I:!z(;,:2,:2-:2:!z(;;,
ou: o!& o!! n:_Jao!>(!oa!(u;;, az u u:n !o!o!
!u !2 o!!oupa:(:I,:I-:I:!z(;,:2,:2-:2:!z(;;,
!u ! !oa!(;(:I,:2;, o::za:ou!:: az ::u,: g!o!!: !o! a!apu
!u !4 !oa!(;(:I,:2;, o::za:ou!:: az !ou,u ::z:: !o! a!apu
!u !5 !oa!(u;(:I,:2;, o::za:ou!:: az u !o! a!apu
}
Itt !U!, !I!4, s !2!5, de knny olyan eseteket elkpzelni, ahol !2, !, s !4 rtke
ms. Vegyk a kvetkez szavakbl ll sorozatot egy nmet sztrbl:
D!a!, D!a, u!, u!u, D!nug
Fggelkek s trgymutat 1202
A nyelv szablyainak megfelelen a fnevek (s csak azok) nagy kezdbetsek, de a ren-
dezs nem klnbzteti meg a kis- s nagybetket.
Egy kis- s nagybetket megklnbztet nmet nyelv rendezs minden D-vel kezdd
szt a u el tenne:
D!a!, D!a, D!nug, u!, u!u
Az a (umlautos a) egyfajta a-nak minsl, gy a el kerl. A legtbb karakterkszletben
azonban az a szmrtke nagyobb a szmrtknl, kvetkezskppen !u(; !u(a;,
a szmrtkeken alapul egyszer alaprtelmezett rendezs pedig a kvetkezket adja:
D!a!, D!nug, D!a, u!, u!u
rdekes feladat lehet egy olyan fggvnyt rni, amely a sztrnak megfelelen helyesen
rendezi ezt a sorozatot (D.6[3]).
A a:(; fggvny egy hastrtket szmt ki (17.6.2.3), ami magtl rtetden
hasttblk ltrehozsakor lehet hasznos.
A :au:Jo:u(; fggvny egy olyan karakterlncot llt el, amelyet ms karakterlncokkal
sszehasonltva ugyanazt az eredmnyt kapjuk, mint amit a paramter-karakterlnccal val
sszehasonlts eredmnyezne. A :au:Jo:u(; clja az, hogy optimlis kdot kszthessnk
az olyan programrszekbl, ahol egy karakterlncot szmos msikkal hasonltunk ssze. Ez
akkor hasznos, ha karakterlncok halmazban egy vagy tbb karakterlncot szeretnnk
megkeresni.
A pn!! oupa:(;, a a:(; s a :au:Jo:u(; fggvnyek megvalstst a uo_oupa:(;,
uo_a:(; s uo_:au:Jo:u(; nyilvnos virtulis fggvnyek meghvsa biztostja. Ezeket
a uo_ fggvnyeket a szrmaztatott osztlyokban fell lehet rni. A ktfggvnyes megol-
ds lehetv teszi a knyvtr azon ksztjnek, aki a nem virtulis fggvnyeket rja, hogy
valamilyen kzs szerepet biztostson minden hvsnak, fggetlenl attl, hogy mit csinl-
nnak a felhasznl ltal megadott uo_ fggvnyek.
A virtulis fggvnyek hasznlata megrzi a Ja-ek tbbalak (polimorfikus) termszett,
de kltsges lehet. A tl sok fggvnyhvs elkerlshez a !oa! pontosan meghatroz-
hatja a hasznlatos jellemzket s brmennyi rtket a gyorsttrba tehet, amennyire csak
szksge van a hatkony vgrehajtshoz (D.2.2).
D. Helyi sajtossgok 1203
A jellemzket !oa!..!u tpus statikus !u tagok azonostjk (D.3). A szabvnyos a:_Ja
s n:_Ja fggvnyek az azonostk s jellemzk kztti sszefggseken alapulnak
(D.3.1). Az azonos fellet s szerep Ja-eknek ugyanazzal az azonostval kell rendel-
keznik, gy a o!!aa:> s a o!!a_,uaua:> (D.4.1.1) azonostja is megegye-
zik. Kvetkezskppen kt Ja-nek biztosan klnbz az azonostja, ha (a !oa! szem-
pontjbl nzve) klnbz fggvnyeket hajtanak vgre, gy ez a helyzet
a unupnua:> s a unu_pna:> esetben is (D.4.2).
D.4.1.1. Nevestett Collate
A o!!a_,uau olyan jellemz, amely a o!!a azon vltozatt nyjtja az adott loklnak,
amelyet a konstruktor karakterlnc-paramtere nevez meg:
up!a !a:: >
!a:: :u..o!!a_,uau . pn!! o!!a> {
pn!!.
,puJ a:!_::!ug> ::!ug_,p,
!:oz: u::! :uu!zo !o!o!
.p!!! o!!a_,uau(ou: a:*, :!z_ : U;,
J!g,!u. u!u: azouo::o : u!u:u Jngg:u,
p:ou.
-o!!a_,uau(;, J!g,!u. :u u::no:
a o!!a> :!:n!!: Jngg:u,!u J!n!:::a
!u uo_oupa:(ou: * , ou: * , ou: * 2, ou: * 2; ou:,
::!ug_,p uo_:au:Jo:u(ou: * , ou: * ; ou:,
!oug uo_a:(ou: * , ou: * ; ou:,
},
gy a o!!a_,uau arra hasznlhat, hogy kivegynk egy o!!a-et egy, a program vg-
rehajtsi krnyezetben lev nevestett loklbl (D.4). A vgrehajtsi krnyezetben
a Ja-eket egyszeren fjlban, adatknt is trolhatjuk. Egy kevsb rugalmas megolds, ha
a jellemzket programszvegknt s adatknt brzoljuk egy _,uau Ja-ben.
A o!!a_,uaua:> osztly olyan Ja, amelynek nincs sajt azonostja (D.3). A lo-
klokban a o!!a_,uau> s a o!!a> felcserlhetk. Azonos lokl esetben
a o!!a s a o!!a_,uau csak az utbbi szerepben s a o!!a_,uau ltal felknlt
tovbbi konstruktorban klnbzik.
Fggelkek s trgymutat 1204
Jegyezzk meg, hogy a _,uau destruktor vdett. Ebbl kvetkezik, hogy loklis (helyi)
vltozknt nem hasznlhatunk _,uau Ja-et:
:o!u J(;
{
o!!a_,uaua:> u,_o!!(;, !a. a u,_o!! uu :zuo!ao J!
}
Ez azt a nzpontot tkrzi, hogy a loklok s jellemzk olyasmik, amiket a legjobb elg-
g magas szinten hasznlni a programban, hogy a program minl nagyobb rszre legynk
hatssal. Erre plda a globlis lokl belltsa (D.2.3) vagy egy adatfolyam megtltse
(21.6.3, D.1). Ha szksges, egy _,uau osztlybl egy nyilvnos destruktorral rendel-
kez osztlyt szrmaztathatunk s ebbl az osztlybl loklis vltozkat hozhatunk ltre.
D.4.2. Szmok be- s kivitele
A szm-kimenetet a unu_pn Ja kezeli, amely egy adatfolyam tmeneti trba r (21.6.4).
A bemenet kezelse a unu_g dolga; ez is tmeneti trbl olvas. A unu_pn s unu_g
ltal hasznlt formtumot a unupnu jellemz hatrozza meg.
D.4.2.1. Szmjegy-formtumok
A beptett tpusok (mint a oo!, az !u, s a uon!) be- s kimeneti formtumt
a unupnu jellemz rja le:
up!a !a:: >
!a:: :u..unupnu . pn!! !oa!..Ja {
pn!!.
,puJ a:_,p,
,puJ a:!_::!ug> ::!ug_,p,
.p!!! unupnu(:!z_ : U;,
u!ua!_po!u(; ou:, a !a::!(; !o!au
on:auu:_:p(; ou:, , a !a::!(; !o!au
::!ug g:onp!ug(; ou:, a !a::!(; !o!au, !u:. u!u: :opo:o:::
::!ug_,p :nuau(; ou:, :n a !a::!(; !o!au
::!ug_,p Ja!:uau(; ou:, Ja!: a !a::!(; !o!au
D. Helyi sajtossgok 1205
:a! !oa!..!u !u, Ja-azouo::o onu (D2, D, DI;
p:ou.
-unupnu(;,
:!:n!!: uo_ Jngg:u, a u,!!:uo: Jngg:u, :zu:a (!:u D4I;
},
A g:onp!ug(; ltal visszaadott karakterlnc karaktereinek beolvassa kis egsz rtkek so-
rozataknt trtnik. Minden szm a szmjegyek szmt hatrozza meg egy csoport szm-
ra. A 0. karakter a jobb szls csoportot adja meg (ezek a legkisebb helyirtk szmje-
gyek), az 1. az attl balra lev csoportot s gy tovbb. gy a `UU4`UU2`UU egy szmot
r le (pl. I2-45-o73U, feltve, hogy a - az elvlasztsra hasznlt karakter). Ha szksges,
a csoportost minta utols karaktere ismtelten hasznlhat, gy a `UU egyenrtk
a `UU`UU`UU-mal. Ahogy az elvlaszt karakter neve, a on:auu:_:p(; mutatja is,
a csoportostst leggyakrabban arra hasznljk, hogy a nagy egszeket olvashatbb te-
gyk. A g:onp!ug(; s on:auu:_:p(; fggvnyek az egszek be- s kimeneti formtumt
is megadjk, a lebegpontos szmok szabvnyos be- s kimenethez azonban nem hasz-
nlatosak, gy nem tudjuk kiratni az I245o73U-et I,24,5o73U-knt csupn azltal,
hogy megadjuk a g:onp!ug(; s on:auu:_:p(; fggvnyeket.
A unupnu osztlybl szrmaztatssal j formtumot adhatunk meg. A M,_pnu jellem-
zben pldul lerhatjuk, hogy az egsz rtkek szmjegyeit szkzkkel elvlasztva s
hrmasval csoportostva, a lebegpontos rtkeket pedig eurpai stlus szerint, tizedes-
vesszvel elvlasztva kell kirni:
!a:: M,_pnu . pn!! :u..unupnua:> {
pn!!.
,puJ a: a:_,p,
,puJ ::!ug ::!ug_,p,
.p!!! M,_pnu(:!z_ : U; . :u..unupnua:>(:; { }
p:ou.
a: uo_u!ua!_po!u(; ou: { :n:u ,, } :::zo
a: uo_on:auu:_:p(; ou: { :n:u , } :zooz
::!ug uo_g:onp!ug(; ou: { :n:u `UU, } :zug,n :opo:o
},
:o!u J(;
{
on E!:o ::!n:. I245o73 *** I245o73 `u,
!oa! !o(!oa!(;, uu M,_pnu;,
on!un(!o;,
on M:ou! ::!n:. I245o73 *** I245o73 `u,
}
Fggelkek s trgymutat 1206
Ez a kvetkez eredmnyt adja:
E!:o ::!n:. I245o73 *** I2457-Uo
M:ou! ::!n:. I2 45 o73 *** I,2457-Uo
Jegyezzk meg, hogy az !un(; az adatfolyamban msolatot trol paramterrl. Kvet-
kezskppen az adatfolyam akkor is tmaszkodhat egy megtlttt loklra, ha annak erede-
ti pldnya mr nem ltezik. Ha a bemeneti adatfolyam szmra be van lltva a oo!a!pa
jelzbit (21.2.2, 21.4.1), a :n s Ja!: rtkeket a :nuau(; s a Ja!:uau(; ltal
visszaadott karakterlncok jellhetik, ms esetben a U s az I.
A unupnu _,uau vltozata (D.4, D.4.1) is adott:
up!a !a:: >
!a:: :u..unupnu_,uau . pn!! unupnu> { * * },
D.4.2.2. Szmok kirsa
Az tmeneti trba val rskor (21.6.4) a kimeneti adatfolyamok (o::au) a unu_pn jel-
lemzre tmaszkodnak:
up!a !a:: , !a:: On o::aunJ_!:ao:> >
!a:: :u..unu_pn . pn!! !oa!..Ja {
pn!!.
,puJ a:_,p,
,puJ On !:_,p,
.p!!! unu_pn(:!z_ : U;,
a : : !!,z: az : auaJo!,au uu! :ua poz:!o:a.
On pn(On , !o:_a:& :, J!!!, oo! :; ou:,
On pn(On , !o:_a:& :, J!!!, !oug :; ou:,
On pn(On , !o:_a:& :, J!!!, nu:!guu !oug :; ou:,
On pn(On , !o:_a:& :, J!!!, uon! :; ou:,
On pn(On , !o:_a:& :, J!!!, !oug uon! :; ou:,
On pn(On , !o:_a:& :, J!!!, ou: :o!u* :; ou:,
:a! !oa!..!u !u, Ja-azouo::o onu (D2, D, DI;
p:ou.
-unu_pn(;,
:!:n!!: uo_ Jngg:u, a u,!!:uo: Jngg:u, :zu:a (!:u D4I;
},
D. Helyi sajtossgok 1207
Az On kimeneti bejr (itertor) paramter azonostja, hogy a pn(; a szmrtket jell ka-
raktereket hol helyezi el a kimeneti adatfolyam tmeneti trban (21.6.4). A pn(; rtke az
a bejr (iterator), amely egy hellyel az utols karakter mg mutat.
Jegyezzk meg, hogy a unu_pn alaprtelmezett vltozata (amelynek bejrjval
o::aunJ_!:ao:> tpus karakterekhez lehet hozzfrni) a szabvnyos !oa!-ek
(D.4) rsze. Ha ms vltozatot akarunk hasznlni, akkor azt magunknak kell elksztennk:
up!a!a:: >
!a:: S:!ug_unupn . pn!! :u..unu_pn, ,puau a:!_::!ug>..!:ao:> {
pn!!.
S:!ug_unupn(; . unu_pn, ,puau a:!_::!ug>..!:ao:>(I; { }
},
:o!u J(!u !, ::!ug& :, !u po:; ! Jo:uz:a :-, a po: poz:!oo! zu:
{
S:!ug_unupna:> J,
!o:_a:& ... on, a on Jo:uz:! :za!,a!ua a:zu!aa
Jpn(:g!u(;-po:, ..., , !;, ! Jo:uz:a :-
}
Az !o:_a: paramterrel a formtumrl s a loklrl kaphatunk informcit. Pldul ha
res helyeket kell kitltennk, az !o:_a: paramter ltal megadott J!!! karakter lesz fel-
hasznlva. Az tmeneti tr, amelybe -n keresztl runk, ltalban ahhoz az o::au-hez
kapcsoldik, amelynek : a bzisosztlya. Az !o:_a: objektumokat nem knny ltrehoz-
ni, mert a formtummal kapcsolatban tbb dolgot is szablyoznak s ezeknek egysgesnek
kell lennik, hogy a kimenet elfogadhat legyen. Kvetkezskppen az !o:_a: osztly-
nak nincs nyilvnos konstruktora (21.3.3).
A pn(; fggvnyek szintn !o:_a: paramtereket hasznlnak az adatfolyam lokljnak le-
krdezshez. A lokl hatrozza meg az elvlaszt karaktereket (D.4.2.1), a logikai rtkek
szveges brzolst s a -ra val talaktst. Pldul ha feltesszk, hogy a pn(; fgg-
vny !o:_a: paramtere :, a pn(; fggvnyben ehhez hasonl kdot tallhatunk:
ou: !oa!& !o :g!o(;,
ua:_ u n:_Ja ,pa:> >(!o;u!uu(;, a!a:: a:-:o! -:a
::!ug pu n:_Ja unupnua:> >(!o;u!ua!_po!u(;, a!ap:!uz:.
::!ug J!: n:_Ja unupnua:> >(!o;Ja!:uau(;, a!ap:!uz:. Ja!:
Fggelkek s trgymutat 1208
A unu_pna:>-hoz hasonl szabvnyos Ja-eket a szabvnyos I/O adatfolyam-fgg-
vnyek ltalban automatikusan hasznljk, gy a legtbb programoznak nem is kell tud-
nia rluk. rdemes azonban szemgyre venni, hogy a standard knyvtr fggvnyei ho-
gyan hasznljk a jellemzket, mert jl mutatja, hogyan mkdnek a be- s kimeneti
adatfolyamok, illetve a Ja-ek. Mint mindig, a standard knyvtr most is rdekes progra-
mozsi eljrsokra mutat pldkat.
A unu_pn felhasznlsval az o::au ksztje a kvetkezket rhatja:
up!a!a:: , !a:: T:>
o::au& :u..a:!_o::au,T:>..op:ao:(uon! u;
{
:u:, gna:u(*!:;, !:u 2I3
!J (:gna:u; :n:u *!:,
:, {
!J (n:_Ja unu_pn> >(g!o(;;pn(*!:,*!:,!:->J!!!(;,u;Ja!!u(;;
::a(au!;,
}
a (; {
auu!_!o.p!ou(*!:;,
}
:n:u *!:,
}
Itt sok minden trtnik. Az rszem (sentry) biztostja, hogy minden mvelet vgrehajt-
dik (21.3.8). Az o::au lokljt a g!o(; tagfggvny meghvsval kapjuk meg, majd
a loklbl a n:_Ja sablon fggvnnyel (D.3.1) kiszedjk a unu_pn jellemzt. Miutn
ezt megtettk, meghvjuk a megfelel pn(; fggvnyeket az igazi munka elvgzshez.
A pn(; els kt paramtert knnyen megadhatjuk, hiszen az o::au-bl ltrehozhatjuk
az o::au_nJ bejrt (19.2.6), az adatfolyamot pedig automatikusan !o:_a: bzisosz-
tlyra alakthatjuk (21.2.1).
A pn(; kimeneti bejr paramtert adja vissza. A bejrt egy a:!_o::au-bl szerzi
meg, gy annak tpusa o::aunJ_!:ao:. Kvetkezskppen a Ja!!u(; (19.2.6.1) rendel-
kezsnkre ll a hibaellenrzshez s lehetv teszi szmunkra, hogy megfelelen bellt-
hassuk az adatfolyam llapott.
Nem hasznltuk a a:_Ja fggvnyt, mert a szabvnyos Ja-ek (D.4) garantltan ott
vannak minden loklban. Ha ez a garancia nem ll fenn, au_a: kivtel kivltsra kerl
sor (D.3.1).
D. Helyi sajtossgok 1209
A pn(; a uo_pn virtulis fggvnyt hvja meg. Kvetkezskppen lehet, hogy felhasznli
kd hajtdik vgre s az op:ao:(;-nek fel kell kszlnie arra, hogy a fellrt uo_pn(;
ltal kivltott kivtelt kezelje. Tovbb lehet, hogy a unu_pn nem ltezik valamilyen ka-
raktertpusra, gy a n:_Ja(; az :u..au_a: kivtelt vlthatja ki (D.3.1). A beptett t-
pusokra, mint amilyen a uon!, a viselkedst a C++ szabvny rja le. Kvetkezskp-
pen nem az a krds, hogy a auu!_!o.p!ou(; fggvnynek mit kell csinlnia, hanem
az, hogyan csinlja azt, amit a szabvny elr. Ha a au! jelzbit az o::au kivtel lla-
potra van lltva (21.3.6), a kivtel tovbbdobsra kerl sor, ms esetben a kivtel keze-
lse az adatfolyam llapotnak belltst s a vgrehajts folytatst jelenti. A au! jelz-
bitet mindkt esetben az adatfolyam llapotra kell lltani (21.3.3):
up!a!a:: , !a:: T:>
:o!u auu!_!o.p!ou(:u..a:!_o::au,T:>& :; a a ::zo! ug:::a
{
!J (:.p!ou:(;&!o:_a:..au!; {
:, {
:::a(!o:_a:..au!;, } a(; { }
:ou, o:uo:
}
:::a(!o:_a:..au!;, a:!_!o:..Ja!!n: !:! :!a !
}
A :, blokk azrt szksges, mert a ::a(; a:!_!o:..Ja!!n: kivtelt vlthat ki (21.3.3,
21.3.6). Ha azonban a au! a kivtel llapotra lltott, az op:ao:(;-nek tovbb kell
dobnia azt a kivtelt, amely a auu!_!o.p!ou(; meghvst okozta (nem pedig egysze-
ren a:!_!o:..Ja!!n: kivtelt kell kivltania).
A -t gy kell megvalstani a beptett tpusokra, pldul a uon!-ra, hogy kzvetlenl
az adatfolyam tmeneti trba rjunk. Ha a -t felhasznli tpusra rjuk meg, az ebbl ere-
d nehzsgeket gy kerlhetjk el, hogy a felhasznli tpusok kimenett mr meglv t-
pusok kimenetvel fejezzk ki (D.3.2).
D.4.2.3. Szmok bevitele
A bemeneti adatfolyamok (!::au) a unu_g jellemzre tmaszkodnak az tmeneti trbl
(21.6.4) val olvasshoz:
up!a !a:: , !a:: 1u !::aunJ_!:ao:> >
!a:: :u..unu_g . pn!! !oa!..Ja {
pn!!.
,puJ a:_,p,
,puJ 1u !:_,p,
Fggelkek s trgymutat 1210
.p!!! unu_g(:!z_ : U;,
o!:a:: /.;-o! :-, az :-!! Jo:uz:! :za!,o a:zu!a:a!,
!a!z: az : !!:::a!.
1u g(1u , 1u , !o:_a:& :, !o:_a:..!o:a& :, oo!& :; ou:,
1u g(1u , 1u , !o:_a:& :, !o:_a:..!o:a& :, !oug& :; ou:,
1u g(1u , 1u , !o:_a:& :, !o:_a:..!o:a& :, nu:!guu :o:& :; ou:,
1u g(1u , 1u , !o:_a:& :, !o:_a:..!o:a& :, nu:!guu !u& :; ou:,
1u g(1u , 1u , !o:_a:& :, !o:_a:..!o:a& :, nu:!guu !oug& :; ou:,
1u g(1u , 1u , !o:_a:& :, !o:_a:..!o:a& :, J!oa& :; ou:,
1u g(1u , 1u , !o:_a:& :, !o:_a:..!o:a& :, uon!& :; ou:,
1u g(1u , 1u , !o:_a:& :, !o:_a:..!o:a& :, !oug uon!& :; ou:,
1u g(1u , 1u , !o:_a:& :, !o:_a:..!o:a& :, :o!u*& :; ou:,
:a! !oa!..!u !u, Ja-azouo::o onu (D2, D, DI;
p:ou.
-unu_g(;,
:!:n!!: uo_ Jngg:u, a u,!!:uo: Jngg:u, :zu:a (!:u D4I;
},
A unu_g szerkezete alapveten a unu_pn-hoz (D.4.2.2) hasonl. Mivel inkbb olvas,
mint r, a g(;-nek egy bejrprra van szksge, az olvass clpontjt meghatroz para-
mter pedig egy referencia. Az !o:a tpus : vltoz gy van belltva, hogy tkrzze az
adatfolyam llapott. Ha a kvnt tpus rtket nem lehet beolvasni, az :-ben a Ja!!! be-
lltsra kerl sor, ha elrtk a bemenet vgt, az oJ!-re. A bemeneti mveletek az :-t
arra hasznljk, hogy eldntsk, hogyan lltsk be az adatfolyam llapott. Ha nem trtnt
hiba, a beolvasott rtk a :-n keresztl rtkl addik; egybknt a : vltozatlan marad.
Az !::au ksztje a kvetkezket rhatja:
up!a!a:: , !a:: T:>
!::au& :u..a:!_!::au,T:>..op:ao:>>(uon!& u;
{
:u:, gna:u(*!:;, !:u 2I3
!J (:gna:u; :n:u *!:,
!o:a :a U, o
!::aunJ_!:ao:> o:,
uon! uu,
:, {
n:_Ja unu_g> >(g!o(;;g(*!:,o:,*!:,:a,uu;,
}
D. Helyi sajtossgok 1211
a (; {
auu!_!o.p!ou(*!:;, !:u D422
:n:u *!:,
}
!J (:aU '' :aoJ!; u uu, u :u !!::a :a ao:,
a a g(; :!::! :
::a(:a;,
:n:u *!:,
}
Az !::au szmra megengedett kivteleket hiba esetn a ::a(; fggvny vltja ki
(21.3.6).
Egy unupnu jellemzt mint amilyen a u,_unupnu a D.4.2 pontban megadva nem
szabvnyos elvlaszt karaktereket hasznlva is olvashatunk:
:o!u J(;
{
on E!:o ::!n:.
!u !I,
uon! uI,
!u >> !I >> uI, o!:a:: a :za:u,o: I245o73 Jo:ua a:zu!a:a!
!oa! !o(!oa!..!a::!(;, uu M,_pnu;,
!u!un(!o;,
on M:ou! ::!n:.
!u !2,
uon! u2,
!u >> !I >> u2, o!:a:: a I2 45 o73 Jo:ua a:zu!a:a!
}
Ha igazn ritkn hasznlt szmformtumokat szeretnnk beolvasni, fell kell rnunk
a uo_g(; fggvnyt. Megadhatunk pldul egy unu_g Ja-et, amely rmai szmokat
olvas be ( AA1 vagy MM, D.6[15]).
D.4.3. Pnzrtkek be- s kivitele
A pnzsszegek formzsnak mdja az egyszer szmok formzshoz hasonlt
(D.4.2), az elbbinl azonban a kulturlis eltrsek jelentsge nagyobb. A negatv ssze-
geket (vesztesg, tartozs, mondjuk -1,25) pldul egyes helyeken pozitv szmokknt, z-
rjelben kell feltntetni (1,25). Az is elfordulhat, hogy a negatv sszegek felismersnek
megknnytsre szneket kell hasznlnunk.
Fggelkek s trgymutat 1212
Nincs szabvnyos pnz tpus. Ehelyett kifejezetten a pnz Ja-eket kell hasznlnunk
az olyan szmrtkeknl, amelyekrl tudjuk, hogy pnzsszegeket jelentenek:
!a:: Mou, { g,:z:n :pn: puzo::zg :o!::a
!oug !u auonu,
pn!!.
Mou,(!oug !u !; . auonu(!; { }
op:ao: !oug !u(; ou: { :n:u auonu, }
},
:o!u J(!oug !u !;
{
on E: ! O::zg Mou,(!; uu!,
}
Ezen Ja-ek feladata az, hogy jelentsen megknnytsk az olyan kimeneti mveletek
megrst a Mou, tpusra, melyek az sszeget a helyi szoksoknak megfelelen rjk ki
(lsd D.4.3.2-t). A kimenet a on lokljtl fggen vltozik:
E: I245o7 O::zg !I245o7
E: I245o7 O::zg I245,o7 DKK
E: -I245o7 O::zg !-I245o7
E: -I245o7 O::zg -!I245o7
E: -I245o7 O::zg (H1I245,o7;
A pnzrtkek esetben rendszerint alapvet a legkisebb pnzegysgre is kiterjed pontos-
sg. Kvetkezskppen n azt a szokst kvetem, hogy inkbb a fillrek (penny, re, cent
stb.) szmt brzolom egsz rtkekkel, nem a forintokt (font, korona, dnr, eur stb.).
Ezt a megoldst a uou,_pnu J:a_u!g!:(; fggvnye tmogatja (D.4.3.1). A tizedes-el-
vlasztt a u!ua!_po!u(; adja meg.
A uou,_a: jellemz ltal lert formtumon alapul bemenetet s kimenetet kezel fgg-
vnyeket a uou,_g s uou,_pn Ja-ek biztostjk.
A be- s kimeneti formtum szablyozsra s a pnzrtkek trolsra egy egyszer
Mou, tpust hasznlhatunk. Az els esetben a pnzsszegek trolsra hasznlt (ms) t-
pusokat kirs eltt a Mou, tpusra alaktjuk, a beolvasst pedig szintn Mou, tpus vl-
tozkba vgezzk, mieltt az rtkeket ms tpusra alaktannk. Kevesebb hibval jr, ha
a pnzsszegeket kvetkezetesen a Mou, tpusban troljuk: gy nem feledkezhetnk meg
arrl, hogy egy rtket Mou, tpusra alaktsunk, mieltt kirnnk s nem kapunk bemene-
ti hibkat, ha a lokltl fggetlenl prblunk pnzsszegeket beolvasni. Lehetsges azon-
ban, hogy a Mou, tpus bevezetse kivitelezhetetlen, ha a rendszer nincs felksztve r.
Ilyen esetekben szksges a Mou,-konverzikat alkalmazni az olvas s r mveleteknl.
D. Helyi sajtossgok 1213
D.4.3.1. A pnzrtkek formtuma
A pnzsszegek megjelentst szablyoz uou,pnu termszetesen a kznsges sz-
mok formtumt megad unupnu Ja-re (D.4.2.1) hasonlt:
!a:: :u..uou,_a: {
pn!!.
unu pa: { uou, :pa, :,uo!, :!gu, :a!n }, az !:uuz: ::z!
::n pa:u { a: J!!u/4], }, !:uuz:
},
up!a !a:: , oo! 1u:ua!oua! Ja!:>
!a:: :u..uou,pnu . pn!! !oa!..Ja, pn!! uou,_a: {
pn!!.
,puJ a:_,p,
,puJ a:!_::!ug> ::!ug_,p,
.p!!! uou,pnu(:!z_ : U;,
u!ua!_po!u(; ou:, a !a::!(; !o!au
on:auu:_:p(; ou:, , a !a::!(; !o!au
::!ug g:onp!ug(; ou:, a !a::!(; !o!au, !u:. u!u: :opo:o:::
::!ug_,p n::_:,uo!(; ou:, ! a !a::!(; !o!au
::!ug_,p po:!!:_:!gu(; ou:, a !a::!(; !o!au
::!ug_,p uga!:_:!gu(; ou:, - a !a::!(; !o!au
!u J:a_u!g!:(; ou:, :zug, :zua a !zu::::zo nu, 2 a !a::!(; !o!au
pa:u po:_Jo:ua(; ou:, { :,uo!, :!gu, uou, :a!n } a !a::!(; !o!au
pa:u ug_Jo:ua(; ou:, { :,uo!, :!gu, uou, :a!n } a !a::!(; !o!au
:a! ou: oo! !u! 1u:ua!oua!, a uuzoz! puzJo:unu a:zu!aa
:a! !oa!..!u !u, Ja-azouo::o onu (D2, D, DI;
p:ou.
-uou,pnu(;,
:!:n!!: uo_ Jngg:u, a u,!!:uo: Jngg:u, :zu:a (!:u D4I;
},
A uou,pnu szolgltatsait elssorban a uou,_pn s uou,_g jellemzk ksztinek
szntk (D.4.3.2, D.4.3.3).
A u!ua!_po!u(;, on:auu:_:p(;, s g:onp!ug(; tagok gy viselkednek, mint a velk
egyenrtk fggvnyek a unupnu Ja-ben.
Fggelkek s trgymutat 1214
A n::_:,uo!(;, po:!!:_:!gu(; s uga!:_:!gu(; tagok rendre a valutajelet (!, +, 1:1,
DK:), a pluszjelet s a mnuszjelet jell karakterlncot adjk vissza. Ha az 1u:ua!oua!
sablonparamter rtke :n volt, az !u! tag szintn :n lesz s a valutajelek nemzetkzi
brzolsa lesz hasznlatos. A nemzetkzi brzols egy ngy karakterbl ll karakterlnc:
USD
DKK
EUR
Az utols karakter ltalban szkz. A hrom bets valuta-azonostt az ISO-4217 szabvny
rja le. Ha az 1u:ua!oua! rtke Ja!:, helyi valutajelet !, + vagy + lehet hasznlni.
A po:_Jo:ua(; s ug_Jo:ua(; ltal visszaadott minta (pa:u) ngy rszbl (pa:) ll,
amelyek a szmrtk, a valutajel, az eljel s az reshely megjelentsnek sorrendjt adjk
meg. A leggyakoribb formtumok ezt a mintt kvetik:
-! I245 { :!gu, :,uo!, :pa, :a!n }, ao! a po:!!:_:!gu(; :!::za::! : -
!-I245 { :,uo!, :!gu, :a!n, uou }, ao! a po:!!:_:!gu(; :!::za::! : -
!I245 { :,uo!, :!gu, :a!n, uou }, ao! a po:!!:_:!gu(; :!::za::! :
!I245- { :,uo!, :a!n, :!gu, uou }
-I245 DKK { :!gu, :a!n, :pa, :,uo! }
(!I245; { :!gu, :,uo!, :a!n, uou }, ao! a uga!:_:!gu(; :!::za::! : (;
(I245DKK; { :!gu, :a!n, :,uo!, uou }, ao! a uga!:_:!gu(; :!::za::! : (;
A negatv szmok zrjeles brzolst a uga!:_:!gu(; fggvny visszatrsi rtkeknt
a (; karakterekbl ll karakterlncot definilva biztostjuk. Az eljel-karakterlnc els ka-
raktere oda kerl, ahol a :!gu (eljel) tallhat a mintban, a maradk pedig a minta tbbi
rsze utn kvetkezik. Ezt a megoldst leggyakrabban ahhoz a szoksos pnzgyi jells-
hez hasznljk, miszerint a negatv sszegeket zrjelben tntetik fel, de msra is fel lehet
hasznlni:
-!I245 { :!gu, :,uo!, :a!n, uou }, ao! a uga!:_:!gu(; :!::za::! : -
*!I245 :!!!, { :!gu, :,uo!, :a!n, uou }, ao! a uga!:_:!gu(;
:!::za::! : * :!!!,
Az eljel, rtk s szimblum (:!gu, :a!n, :,uo!) rtkek csak egyszer szerepelhetnek
a mintban. A maradk rtk :pa (reshely) vagy uou (semmi) lehet. Ahol :pa szere-
pel, oda legalbb egy reshely karakternek kell kerlnie, a uou nulla vagy tbb reshely
karaktert jelent (kivve ha a uou a minta vgn szerepel).
D. Helyi sajtossgok 1215
Ezek a szigor szablyok nhny ltszlag sszer mintt is megtiltanak:
pa:u pa { :!gu, :a!n, uou, uou }, !a. a :,uo! u!u: ugau:a
A u!ua!_po!u(; helyt a J:a_u!g!:(; fggvny jelli ki. A pnzsszegeket ltalban
a legkisebb valutaegysggel brzoljk (D.4.3), ami jellemzen a f egysg szzadrsze
(pldul cent s dollr), gy a J:a_u!g!:(; rtke ltalban 2.
Kvetkezzen egy egyszer formtum, Ja-knt megadva:
!a:: M,_uou,_!o . pn!! uou,pnua:,:n> {
pn!!.
.p!!! M,_uou,_!o(:!z_ : U; . uou,pnua:,:n>(:; { }
a:_,p uo_u!ua!_po!u(; ou: { :n:u , }
a:_,p uo_on:auu:_:p(; ou: { :n:u ,, }
::!ug uo_g:onp!ug(; ou: { :n:u `UU`UU`UU, }
::!ug_,p uo_n::_:,uo!(; ou: { :n:u USD , }
::!ug_,p uo_po:!!:_:!gu(; ou: { :n:u , }
::!ug_,p uo_uga!:_:!gu(; ou: { :n:u (;, }
!u uo_J:a_u!g!:(; ou: { :n:u 2, } 2 :zug, a !zu::::zo nu
pa:u uo_po:_Jo:ua(; ou:
{
:a! pa:u pa { :!gu, :,uo!, :a!n, uou },
:n:u pa,
}
pa:u uo_ug_Jo:ua(; ou:
{
:a! pa:u pa { :!gu, :,uo!, :a!n, uou },
:n:u pa,
}
},
Ezt a Ja-et hasznljuk a Mou, albbi be- s kimeneti mveleteiben is (D.4.3.2 s
D.4.3.3).
A uou,pnu _,uau vltozata (D.4, D.4.1) is adott:
up!a !a:: , oo! 1u! Ja!:>
!a:: :u..uou,pnu_,uau . pn!! uou,pnu, 1u!> { * * },
Fggelkek s trgymutat 1216
D.4.3.2. Pnzrtkek kirsa
A uou,_pn a uou,pnu ltal meghatrozott formtumban rja ki a pnzsszegeket.
Pontosabban, a uou,_pn olyan pn(; fggvnyeket nyjt, amelyek megfelelen form-
zott karakter-brzolsokat tesznek egy adatfolyam tmeneti trba:
up!a !a:: , !a:: On o::aunJ_!:ao:> >
!a:: :u..uou,_pn . pn!! !oa!..Ja {
pn!!.
,puJ a:_,p,
,puJ On !:_,p,
,puJ a:!_::!ug> ::!ug_,p,
.p!!! uou,_pn(:!z_ : U;,
a : : !!,z: az uu! : poz:!o:a.
On pn(On , oo! !u!, !o:_a:& :, J!!!, !oug uon! :; ou:,
On pn(On , oo! !u!, !o:_a:& :, J!!!, ou: ::!ug_,p& :; ou:,
:a! !oa!..!u !u, Ja-azouo::o onu (D2, D, DI;
p:ou.
-uou,_pn(;,
:!:n!!: uo_ Jngg:u, a u,!!:uo: Jngg:u, :zu:a (!:u D4I;
},
A , :, J!!! s : paramterek ugyanarra hasznlatosak, mint a unu_pn jellemz pn(; fgg-
vnyeiben (D.4.3.2.2). Az !u! paramter jelzi, hogy a szabvnyos ngykarakteres nemzet-
kzi valutaszimblum vagy helyi valutajel hasznlatos-e (D.4.3.1).
Ha adott a uou,_pn jellemz, a Mou, osztly szmra(D.4.3) kimeneti mveletet rhatunk:
o::au& op:ao:(o::au& :, Mou, u;
{
o::au..:u:, gna:u(:;, !:u 2I3
!J (:gna:u; :n:u :,
:, {
ou: uou,_pna:>& J n:_Ja uou,_pna:> >(:g!o(;;,
!J (u:a!_a:!oug uon!>(u;; { u !oug uon!-u :zo!ao
!J (Jpn(:,:n,:,:J!!!(;,u;Ja!!u(;; :::a(!o:_a:..au!;,
}
!: {
o::!ug::au :,
: u, a:a:!u-:zo!::a a!a:
D. Helyi sajtossgok 1217
!J (Jpn(:,:n,:,:J!!!(;,:::(;;Ja!!u(;; :::a(!o:_a:..au!;,
}
}
a (; {
auu!_!o.p!ou(:;, !:u D422
}
:n:u :,
}
Ha a !oug uon! nem elg pontos a pnzrtk brzolshoz, az rtket karakterlncc
alaktjuk s azt rjuk ki az ilyen paramtert vr pn(; fggvnnyel.
D.4.3.3. Pnzrtkek beolvassa
A uou,_g a uou,pnu ltal meghatrozott formtumnak megfelelen olvassa be
a pnzsszegeket. Pontosabban, a uou,_g olyan g(; fggvnyeket nyjt, amelyek
a megfelelen formzott karakteres brzolst olvassk be egy adatfolyam tmeneti trbl:
up!a !a:: , !a:: 1u !::aunJ_!:ao:> >
!a:: :u..uou,_g . pn!! !oa!..Ja {
pn!!.
,puJ a:_,p,
,puJ 1u !:_,p,
,puJ a:!_::!ug> ::!ug_,p,
.p!!! uou,_g(:!z_ : U;,
o!:a:: /.;-o! :-, az :-!! Jo:uz:! :za!,o a:zu!a:a!,
!a!z: az : !!:::a!.
1u g(1u , 1u , oo! !u!, !o:_a:& :, !o:_a:..!o:a& :, !oug uon!& :; ou:,
1u g(1u , 1u , oo! !u!, !o:_a:& :, !o:_a:..!o:a& :, ::!ug_,p& :; ou:,
:a! !oa!..!u !u, Ja-azouo::o onu (D2, D, DI;
p:ou.
-uou,_g(;,
:!:n!!: uo_ Jngg:u, a u,!!:uo: Jngg:u, :zu:a (!:u D4I;
},
A , :, J!!!, s : paramterek ugyanarra hasznlatosak, mint a unu_g jellemz g(; fgg-
vnyeiben (D.4.3.2.2). Az !u! paramter jelzi, hogy a szabvnyos ngykarakteres nemzet-
kzi valutaszimblum vagy helyi valutajel hasznlatos-e (D.4.3.1).
Fggelkek s trgymutat 1218
Megfelel uou,_g s uou,_pn jellemzprral olyan formban adhatunk kimenetet,
amelyet hiba s adatveszts nlkl lehet visszaolvasni:
!u ua!u(;
{
Mou, u,
u!! (!u>>u; on u `u,
}
Ez az egyszer program kimenett el kell, hogy fogadja bemenetknt is. St, ha a progra-
mot msodszor is lefuttatjuk az els futtats eredmnyvel, a kimenetnek meg kell egyez-
nie a program eredeti bemenetvel.
A Mou, osztly szmra a kvetkez megfelel bemeneti mvelet lehet:
!::au& op:ao:>>(!::au& :, Mou,& u;
{
!::au..:u:, gna:u(:;, !:u 2I3
!J (gna:u; :, {
!o:_a:..!o:a :a U, o
!::aunJ_!:ao:a:> o:,
::!ug ::,
n:_Ja uou,_ga:> >(:g!o(;;g(:,o:,:n,:a,::;,
!J (:aU '' :a!o:_a:..oJ!; { :a ao: !!: :,
a a g(; :!::! :
!oug !u ! ::o!(::_::(;,U,U;,
!J (::uoERNE;
:a ' !o:_a:..Ja!!!,
!:
u !, :a ao: !!:a u :, a az a!a:: !oug !u-: :!:n!
:::a(:a;,
}
}
a (; {
auu!_!o.p!ou(:;, !:u D422
}
:n:u :,
}
D. Helyi sajtossgok 1219
D.4.4. Dtum s id beolvassa s kirsa
Sajnos a C++ standard knyvtra nem nyjt megfelel dtum tpust, de a C standard knyv-
trbl alacsonyszint eszkzket rklt a dtumok s idtartomnyok kezelshez. Ezek
a C-beli eszkzk szolglnak a C++ rendszerfggetlen idkezel eszkzeinek alapjul.
A kvetkezkben azt mutatjuk be, hogyan igazthat a dtum s id megjelentse a lokl-
hoz, tovbb pldkat adunk arra, hogyan illeszthet be egy felhasznli tpus (Da) az
!o::au (21. fejezet) s !oa! (D.2) ltal nyjtott szerkezetbe. A Da tpuson keresztl
olyan eljrsokkal is megismerkednk, amelyek segthetik az idkezelst, ha nem ll ren-
delkezsnkre a Da tpus.
D.4.4.1. rk s idztk
A legtbb rendszer a legalacsonyabb szinten rendelkezik egy finom idztvel. A standard
knyvtr a !o(; fggvnyt bocstja rendelkezsnkre, amely megvalsts-fgg !o_
tpus rtkkel tr vissza. A !o(; eredmnye a 1OK_PER_SE makr segtsgvel sza-
blyozhat. Ha nincs hozzfrsnk megbzhat idmr eszkzhz, akkor gy mrhetjk
meg egy ciklus idejt:
!u ua!u(!u a:g, a:* a:g:/]; oI7
{
!u u ao!(a:g:/I];, 2U4I
!o_ I !o(;,
!J (I !o_(-I;; { !o_(-I; !u:. a !o(; uu unou!
:: Sauo: u!u: o:u`u,
.!(I;,
}
Jo: (!u ! U, ! u, !--; uo_:ou!ug(;, !uoz:o !!n:
!o_ 2 !o(;,
!J (2 !o_(-I;; {
:: T!:o:un!:`u,
.!(2;,
}
on uo_:ou!ug(; u a!a!ouua! :a!o :g:a:a
uon!(2-I;1OKS_PER_SE u:oup: : !gu,
(u::! :zu,:g. 1OKS_PER_SE p: u:oup:;`u,
}
Fggelkek s trgymutat 1220
Az oszts eltt vgrehajtott uon!(2-I; talakts azrt szksges, mert a !o_ lehet,
hogy egsz tpus. Az, hogy a !o(; mikor kezd futni, az adott nyelvi vltozattl fgg;
a fggvny az egyes programrszek futsi idejnek mrsre val. A !o(; ltal vissza-
adott I s 2 rtkeket alapul vve a uon!(2-I;1OK_PER_SE a rendszer legjobb k-
zeltse kt hvs kzt eltelt idre (msodpercben).
Ha az adott feldolgozegysgre nincs megadva a !o(; fggvny vagy ha az id tl hossz
ahhoz, hogy mrhet legyen, a !o(; a !o_(-I; rtket adja vissza.
A !o(; fggvny a msodperc tredktl legfeljebb nhny msodpercig terjed idtar-
tomnyok mrsre val. Pldul ha a !o_ egy 32 bites eljeles egsz s
a 1OK_PER_SE rtke 1 000 000, a !o(; fggvnnyel az idt 0-tl valamivel tbb mint
2000 msodpercig (krlbell fl rig) mrhetjk (a msodperc milliomod rszben).
A programokrl lnyegi mrseket kszteni nem knny. A gpen fut tbbi program je-
lentsen befolysolhatja az adott program futsi idejt, nehz megjsolni a gyorsttrazs
s az utastscsvek hatsait s az algoritmusok nagymrtkben fgghetnek az adatoktl is.
Ha meg akarjuk mrni egy program futsi idejt, futtassuk tbbszr s vegyk hibsnak
azokat az eredmnyeket, amelyek jelentsen eltrnek a tbbitl.
A hosszabb idtartomnyok s a naptri id kezelsre a standard knyvtr a !u_ tpust
nyjtja, amely egy idpontot brzol; valamint a u szerkezetet, amely az idpontokat r-
szeikre bontja:
,puJ megvalsts_fgg !u_, ug:a!o:::-Jnggo a:!u!a! :pn: (4II;
p: !uoa:ouu, :zo!::a,
!a!au 2 !: g:z
::n u {
!u u_:, a p: u:oup:! /U,oI], a oU : a oI :zoo-u:oup:
!u u_u!u, az o:a p:! /U,5U]
!u u_on:, a uap o:! /U,2]
!u u_uua,, a ouap uapa! /I,I]
!u u_uou, az : ouapa! /U,II], a U !u: aun: (J!g,!u. NEM /I.I2];
!u u_,a:, : IUUU oa, a U !u: IUUU, a IU2- 2UU2
!u u_uua,, uapo :a::uap oa /U,o], a U !u: :a::uap
!u u_,ua,, uapo aun: I oa /U,o5], a U !u: aun: I
!u u_!:u:, u,:! !uo:zu:: !zo
},
A szabvny csak azt biztostja, hogy a urendelkezik a fenti emltett !u tpus tagokkal, azt
nem, hogy a tagok ilyen sorrendben szerepelnek vagy hogy nincsenek ms tagok.
D. Helyi sajtossgok 1221
A !u_ s u tpusok, valamint a hozzjuk kapcsold szolgltatsok a !u> s
!u> fejllomnyokban tallhatk:
!o_ !o(;, o:a! :zua a p:og:au !uun!:a oa
!u_ !u(!u_* p;, ::u,: uap:! !uo
uon! u!JJ!u(!u_ 2, !u_ I;, 2-I u:oup:u
u* !oa!!u(ou: !u_* p;, *p : !,! !uo :z:!u
u* gu!u(ou: !u_* p;, *p : g:uu!! ozp!uo (MT; :z:!u, :ag, U
(!:aa!o: u:. oo:u!uau Uu!:::a! T!u, UT;
!u_ u!u(u* pu;, *pu : !u_ Jo:uau, :ag, !u_(-I;
a:* a:!u(ou: u* pu;, *pu g, ::!n: a:a:!ua! :zo!:a
p! Snu Sp Io UI.U.52 IU7`u
a:* !u(ou: !u_* ; { :n:u a:!u(!oa!!u(;;, }
Vigyzzunk: mind a !oa!!u(;, mind a gu!u(; statikusan lefoglalt objektumra mutat
*u tpus rtket ad vissza, vagyis mindkt fggvny kvetkez meghvsa meg fogja vl-
toztatni az objektum rtkt. Ezrt rgtn hasznljuk fel a visszatrsi rtket vagy msol-
juk a u-et olyan memriahelyre, amit mi felgyelnk. Ugyangy az a:!u(; fggvny is
statikusan lefoglalt karaktertmbre hivatkoz mutatt ad vissza.
A u tpus legalbb tzezer vnyi dtumot (ez a legkisebb egsz esetben krlbell
a [-32000,32000] tartomny) kpes brzolni. A !u_ azonban ltalban 32 bites (eljeles)
!oug !u. Ha msodperceket szmolunk, a !u_ nem sokkal tbb, mint 68 vet tud br-
zolni valamilyen 0. vtl mindkt irnyban. Az alapv rendszerint 1970, a hozz tarto-
z alapid pedig janur 1., 0:00 GMT (UTC). Ha a !u_ 32 bites eljeles egsz, akkor 2038-
ban futunk ki az idbl, hacsak nem terjesztjk ki a !u_-t egy nagyobb egsz tpusra,
ahogy azt mr nhny rendszeren meg is tettk.
A !u_ alapveten arra val, hogy a jelenhez kzeli idt brzoljuk, ezrt nem szabad
elvrnunk, hogy kpes legyen az [1902,2038] tartomnyon kvli dtumokat is jellni. Ami
mg ennl is rosszabb, nem minden idkezel fggvny kezeli azonos mdon a negatv
szmokat. A hordozhatsg miatt az olyan rtkeknek, amelyeket u-knt s !u_-knt
is brzolni kell, az [1920,2038] tartomnyba kell esnik. Azoknak, akik az 1970-tl 2038-ig
terjed idkereten kvli dtumokat szeretnnek brzolni, tovbbi eljrsokat kell kidol-
gozniuk ahhoz, hogy ezt megtehessk.
Fggelkek s trgymutat 1222
Ennek egyik kvetkezmnye, hogy az u!u(; hibt eredmnyezhet. Ha az u!u(; pa-
ramtert nem lehet !u_-knt brzolni, a fggvny a !u_(-I; hibajelzst adja vissza.
Ha van egy sokig fut programunk, gy mrhetjk le futsi idejt:
!u ua!u(!u a:g, a:* a:g:/]; oI7
{
!u_ I !u(U;,
uo_a_!o(a:g,a:g:;,
!u_ 2 !u(U;,
uon! u u!JJ!u(2,I;,
on uo_a_!o(; :g:a:a u u:oup:!g a:o`u,
}
Ha a !u(; paramtere nem U, a fggvny eredmnyeknt kapott id rtkl addik
a fggvny !u_ tpusra mutat paramternek is. Ha a naptri id nem elrhet (mond-
juk valamilyen egyedi processzoron), akkor a !u_(-I; rtk addik vissza. A mai dtu-
mot a kvetkezkppen prblhatjuk meg vatosan megllaptani:
!u ua!u(;
{
!u_ ,
!J (!u(&; !u_(-I;; { a !u_(-I; !u:. a !u(; uu unou!
:: z !uo uu !!ap:ao ug`u,
.!(I;,
}
u* g gu!u(&;,
on g->u_uou-I g->u_uua, IUUU-g->u_,a: uu!,
}
D.4.4.2. Egy dtum osztly
Amint a 10.3 pontban emltettk, nem valszn, hogy egyetlen Da tpus minden ignyt
ki tud szolglni. A dtum felhasznlsa tbbfle megvalstst ignyel s a XIX. szzad eltt
a naptrak nagyban fggtek a trtnelem szeszlyeitl. Pldaknt azonban a 10.3-hoz ha-
sonlan kszthetnk egy Da tpust, a !u_ tpust felhasznlva:
!a:: Da {
pn!!.
unu Mou { auI, J, ua:, ap:, ua,, nu, n!, ang, :p, o, uo:, u },
D. Helyi sajtossgok 1223
!a:: 1au_ua {},
Da(!u uu, Mou uu, !u ,,;,
Da(;,
J:!uu o::au& op:ao:(o::au& :, ou: Da& u;,
p:!:a.
!u_ u, :za:u,o: unu- : !uo:zo!:
},
Da..Da(!u uu, Mou uu, !u ,,;
{
u . { U },
!J (uuU '' Iuu; :ou 1au_ua(;, !g,:z:n::. !:u IUI
.u_uua, uu,
!J (uuau '' uuu; :ou 1au_ua(;,
.u_uou uu-I, a u_uou U a!ap
.u_,a: ,,-IUUU, a u_,a: IUUU a!ap
u u!u(&.;,
}
Da..Da(;
{
u !u(U;, a!ap:!uz Da. a ua! uap
!J (u !u_(-I;; :ou 1au_ua(;,
}
A feladat az, hogy a s >> opertorokat a Da tpusra loklfgg mdon valstsuk
meg.
D.4.4.3. Dtum s id kirsa
A unu_pn Ja-hez (D.4.2) hasonlan a !u_pn is pn(; fggvnyeket ad, hogy bejr-
kon keresztl az tmeneti trakba rhassunk:
up!a !a:: , !a:: On o::aunJ_!:ao:> >
!a:: :u..!u_pn . pn!! !oa!..Ja {
pn!!.
,puJ a:_,p,
,puJ On !:_,p,
.p!!! !u_pn(:!z_ : U;,
Fggelkek s trgymutat 1224
::: az : auaJo!,au uu! :a -u ::zn!, az Ju Jo:unu a:zu!a:a!
On pn(On , !o:_a:& :, J!!!, ou: u* ,
ou: * Ju_, ou: * Ju_; ou:,
On pn(On , !o:_a:& :, J!!!, ou: u* , a: Ju, a: uou U; ou:
{ :n:u uo_pn(,:,J!!!,,Ju,uou;, }
:a! !oa!..!u !u, Ja-azouo::o onu (D2, D, DI;
p:ou.
-!u_pn(;,
:!:na! On uo_pn(On, !o:_a:&, , ou: u*, a:, a:; ou:,
},
A pn(,:,J!!!,,Ju_,Ju_; a -ben lv dtumot -n keresztl az : adatfolyam tmeneti t-
rba helyezi. A J!!! karakterek a kitltshez hasznlatosak, ha az szksges. A kimeneti for-
mtumot a p:!uJ(; formzhoz hasonl (Ju_,Ju_; formzsi karakterlnc (vagy form-
tumvezrl) hatrozza meg. A tnyleges kimenethez a p:!uJ(;-hez hasonl (21.8)
formtum hasznlatos, ami a kvetkez klnleges formtumvezrlket tartalmazhatja:
%a A ht napjnak rvidtett neve (pl. Szo)
% A ht napjnak teljes neve (pl. Szombat)
% A hnap rvidtett neve (pl. Feb)
%1 A hnap teljes neve (pl. Februr)
% A dtum s id (pl. Szo Feb 06 21:46:05 1999)
%u A hnap napja [01,31] (pl. 06)
%H ra [00,23] (pl. 21)
%1 ra [01,12] (pl. 09)
% Az v napja [001,366] (pl. 037)
%u Az v hnapja [01,12] (pl. 02)
%M Perc [00,59] (pl. 48)
%p Dleltt/dlutn (am./pm. de./du.) jelzse a 12 rs rhoz (pl. PM)
%S Msodperc [00,61] (pl. 48)
%U Az v hete [00,53] vasrnappal kezdden (pl. 05): az 1. ht az els va-
srnappal kezddik
%u A ht napja [0,6]: a 0 jelenti a vasrnapot (pl. 6)
%W Az v hete [00,53] htfvel kezdden (pl. 05): az 1. ht az els htfvel
kezddik
%. Dtum (pl. 02/06/99)
%A Id (pl.21:48:40)
%, v az vszzad nlkl [00,99] (pl. 99)
% v (pl.1999)
%2 Az idzna jelzse (pl. EST), ha az idzna ismert
D. Helyi sajtossgok 1225
Ezeket az igen rszletes formz szablyokat a bvthet I/O rendszer paramtereiknt
hasznlhatjuk, de mint minden egyedi jellst, ezeket is clszerbb (s knyelmesebb) csak
eredeti feladatuk elltsra alkalmazni.
A fenti formz utastsokon tl a legtbb C++-vltozat tmogatja az olyan mdostkat
(modifier), mint amilyen a mezszlessget (21.8) meghatroz egsz szm (%IUA).
Az id- s dtumformtumok mdosti nem kpezik rszt a C++ szabvnynak, de nhny
platformszabvny, mint a POSIX, ignyelheti azokat. Kvetkezskppen a mdostkat ne-
hz elkerlni, mg akkor is, ha nem tkletesen hordozhatk.
A !u> vagy !u> fejllomnyban tallhat az :p:!uJ(;-hez (21.8) hasonl
::J!u(; fggvny a kimenetet az id- s dtumformz utastsok felhasznlsval hozza
ltre:
:!z_ ::J!u(a:* :, :!z_ ua., ou: a:* Jo:ua, ou: u* up;,
A fggvny legfeljebb ua. karaktert tesz a *up-bl s a Jo:ua-bl a *:-be, a Jo:ua for-
mznak megfelelen:
!u ua!u(;
{
ou: !u ua. 2U, au,ag. aau :z!, og, az ::J!u(;
:oa :u :uuu,z 2U-u! o a:a:
a: nJ/ua.],
!u_ !u(U;,
::J!u(nJ,ua.,%`u,!oa!!u(&;;,
on nJ,
}
A fenti program az alaprtelmezett !a::!(; loklban (D.2.3) egy szerdai napon
Wuu:ua,-t fog kirni, dn loklban ou:uag-ot.
Azok a karakterek, melyek nem rszei a meghatrozott formtumnak, mint a pldban az
jsor karakter, egyszeren bemsoldnak az els (:; paramterbe.
Amikor a pn(; azonost egy J formtumkaraktert (s egy nem ktelez u mdostt), meg-
hvja a uo_pn(; virtulis fggvnyt, hogy az vgezze el a tnyleges formzst:
uo_pn(,:,J!!!,,J,u;.
Fggelkek s trgymutat 1226
A pn(,:,J!!!,,J,u; hvs a pn(; egyszerstett formja, ahol a formtumkarakter (J) s
a mdost (u) pontosan meghatrozott. Ezrt a
ou: a: Ju/] %IUA,
pn(, :, J!!!, , Ju, Ju-:!zoJ(Ju;;,
hvst a kvetkez alakra lehet rvidteni:
pn(, :, J!!!, , A, IU;,
Ha egy formtum tbbjtos karaktereket tartalmaz, annak az alaprtelmezett llapotban
(D.4.6) kell kezddnie s vgzdnie.
A pn(; fggvnyt felhasznlhatjuk arra is, hogy a Da szmra lokltl fgg kimeneti m-
veletet adjunk meg:
o::au& op:ao:(o::au& :, ou: Da& u;
{
o::au..:u:, gna:u(:;, !:u 2I3
!J (:gna:u; :n:u :,
u* up !oa!!u(&uu;,
:, {
!J (n:_Ja !u_pna:> >(:g!o(;;pn(:,:,:J!!!(;,up,.;Ja!!u(;;
:::a(!o:_a:..Ja!!!;,
}
a (; {
auu!_!o.p!ou(:;, !:u D422
}
:n:u :,
}
Mivel nincs szabvnyos Da tpus, nem ltezik alaprtelmezett formtum a dtumok be- s
kivitelre. Itt gy hatroztam meg a %. formtumot, hogy formzknt az . karaktert ad-
tam t. Mivel a g_!u(; fggvny (D.4.4.4) alaprtelmezett formtuma a %., valszn-
leg ez ll legkzelebb a szabvnyhoz. A D.4.4.5 pontban pldt is lthatunk arra, hogyan
hasznlhatunk ms formtumokat.
D. Helyi sajtossgok 1227
D.4.4.4. Dtum s id beolvassa
Mint mindig, a bemenet trkksebb, mint a kimenet. Amikor rtk kirsra runk kdot,
gyakran klnbz formtumok kzl vlaszthatunk. A beolvassnl emellett a hibkkal is
foglalkoznunk kell s nha szmtanunk kell arra, hogy szmos formtum lehetsges.
A dtum s id beolvasst a !u_g jellemzn keresztl kezeljk. Az alaptlet az, hogy
egy lokl !u_g Ja-je el tudja olvasni a !u_pn ltal ltrehozott idket s dtumokat.
Szabvnyos dtum- s idtpusok azonban nincsenek, ezrt a programoz egy !oa!-t
hasznlhat arra, hogy a kimenetet klnfle formtumoknak megfelelen hozza ltre. A k-
vetkez brzolsokat pldul mind ltre lehet hozni egyetlen kimeneti utastssal, gy,
hogy a !u_pn jellemzt (D.4.4.5) klnbz loklokbl hasznljuk:
{auna:, I5 IUUU
Tn::ua, I5 {auna:, IUUU
I5 {au IUUUD
Tn:: I5IUU
A C++ szabvny arra biztat, hogy a !u_g elksztsnl gy fogadjuk el a dtum- s id-
formtumokat, ahogy azt a POSIX s ms szabvnyok elrjk. A problma az, hogy nehz
szabvnyostani a dtum s id beolvassnak brmilyen mdjt, amely egy adott kultr-
ban szablyos. Blcsebb ksrletezni s megnzni, mit nyjt egy adott !oa! (D.6[8]). Ha
egy formtum nem elfogadott, a programoz msik, megfelel !u_g Ja-et kszthet.
Az id beolvassra hasznlt szabvnyos !u_g a !u_a: osztlybl szrmazik:
!a:: :u..!u_a: {
pn!!.
unu uao:u: {
uo_o:u:, u!u: :o::uu, :!g o !u !: :au (p! a uapa;
uu,, uap, ouap, : :o::uu
uu,, ouap, uap, : :o::uu
,uu, :, ouap, uap :o::uu
,uu :, uap, ouap :o::uu
},
},
Ezt a felsorolst arra hasznlhatjuk, hogy egyszerstsk a dtumformtumok elemzst.
Fggelkek s trgymutat 1228
A unu_g -hez hasonlan a !u_g is egy bemeneti bejrpron keresztl fr hozz t-
meneti trhoz:
up!a !a:: , !a:: 1u !::aunJ_!:ao:> >
!a:: !u_g . pn!! !oa!..Ja, pn!! !u_a: {
pn!!.
,puJ a:_,p,
,puJ 1u !:_,p,
.p!!! !u_g(:!z_ : U;,
uao:u: ua_o:u:(; ou: { :n:u uo_ua_o:u:(;, }
o!:a:: /.;-o! u-, az :-!! Jo:uz:! :za!,o a:zu!a:a!, !a!z: az :
!!:::a!.
1u g_!u(1u , 1u , !o:_a:& :, !o:_a:..!o:a& :, u* u; ou:,
1u g_ua(1u , 1u , !o:_a:& :, !o:_a:..!o:a& :, u* u; ou:,
1u g_,a:(1u , 1u , !o:_a:& :, !o:_a:..!o:a& :, u* u; ou:,
1u g_uua,(1u , 1u , !o:_a:& :, !o:_a:..!o:a& :, u* u; ou:,
1u g_uouuau(1u , 1u , !o:_a:& :, !o:_a:..!o:a& :, u* u; ou:,
:a! !oa!..!u !u, Ja-azouo::o onu (D2, D, DI;
p:ou.
-!u_g(;,
:!:n!!: uo_ Jngg:u, a u,!!:uo: Jngg:u, :zu:a (!:u D4I;
},
A g_!u(; a uo_g_!u(; fggvnyt hvja meg. Az alaprtelmezett g_!u(; a %A for-
mtum (D.4.4) felhasznlsval gy olvassa be az idt, ahogy a lokl !u_pn(; fggv-
nye ltrehozza azt. Ugyangy a g_ua(; fggvny a uo_g_ua(;-et hvja meg s az alap-
rtelmezett g_!u(; a %. formtum felhasznlsval (D.4.4) a lokl !u_pn(;
fggvnynek eredmnye szerint olvas.
A Da tpusok legegyszerbb bemeneti mvelete valami ilyesmi:
!::au& op:ao:>>(!::au& :, Da& u;
{
!::au..:u:, gna:u(:;, !:u 2I3
!J (:gna:u; :n:u :,
!o:_a:..!o:a :: U,
u . { U },
!::aunJ_!:ao:a:,a:_:a!:a:> > uu,
D. Helyi sajtossgok 1229
:, {
n:_Ja !u_ga:> >(:g!o(;;g_ua(:,uu,:,::,&.;,
!J (::U '' ::!o:_a:..oJ!;
u Da(.u_uua,,Da..Mou(.u_uou-I;,.u_,a:-IUUU;,
!:
:::a(::;,
}
a (; {
auu!_!o.p!ou(:;, !:u D422
}
:n:u :,
}
A g_ua(:,uu,:,::,&.; hvs az !::au-rl val kt automatikus talaktson alapul: az
els : paramter egy !::aunJ_!:ao: ltrehozsra hasznlatos, a harmadik paramter-
knt szerepl : pedig az !::au bzisosztlyra, az !o:_a:-re alakul t.
A fenti bemeneti mvelet azon dtumok esetben mkdik helyesen, amelyek a !u_ t-
pussal brzolhatk.
Egy egyszer prba a kvetkez lenne:
!u ua!u(;
:, {
Da oua,,
on oua, uu!, ::: %. Jo:unuua!
Da u(I2, Da..ua,, IUU3;,
on u uu!,
Da uu,
u!! (!u >> uu; on uu uu!, az %. Jo:unuua! !:ozo
unuo o!:a::a
}
a (Da..1au_ua; {
on Ro::z unu. a p:og:au !!p`u,
}
A pn_!u _,uau vltozata (D.4, D.4.1) szintn adott:
up!a !a:: , !a:: On o::aunJ_!:ao:> >
!a:: :u..!u_pn_,uau . pn!! !u_pn,On> { * * },
Fggelkek s trgymutat 1230
D.4.4.5. Egy rugalmasabb Date osztly
Ha megprblnnk felhasznlni a D.4.4.2 pontbl a Da osztlyt a D.4.4.3-ban s
D.4.4.4-ben szerepl be- s kimenettel, hamarosan korltokba tkznnk:
1. A Da csak olyan dtumokat tud kezelni, amelyek a !u_ tpussal brzolha-
tk: ez ltalban az [1970,2038] tartomnyt jelenti.
2. A Da csak a szabvnyos formtumban fogadja el a dtumokat brmilyen le-
gyen is az.
3. A Da-nl a bemeneti hibk jelzse elfogadhatatlan.
4. A Da csak a: tpus adatfolyamokat tmogat, nem tetszleges karakter
tpusakat.
Egy hasznosabb bemeneti mvelet a dtumok szlesebb tartomnyt fogadn el, felismer-
ne nhny gyakori formtumot s megbzhatan jelenten a hibkat valamilyen jl hasznl-
hat formban. Ahhoz, hogy ezt elrjk, el kell trnnk a !u_ brzolstl:
!a:: Da {
pn!!.
unu Mou { auI, J, ua:, ap:, ua,, nu, n!, ang, :p, o, uo:, u },
::n 1au_ua {
ou: a:* u,,
1au_ua(ou: a:* p; . u,(p; { }
},
Da(!u uu, Mou uu, !u ,,, !u ua,_oJ_u U;,
Da(;,
:o!u ua_u(u* ; ou:, a Da u :zo!: *- :z!
!u_ ua_!u_(; ou:, a Da !u_ :zo!::a! : :!::za
!u ,a:(; ou: { :n:u ,, }
Mou uou(; ou: { :n:u u, }
!u ua,(; ou: { :n:u u, }
p:!:a.
a: u,
Mou u,
!u ,,
},
Itt az egyszersg kedvrt a (u,u,,; brzolshoz (10.2) trtnk vissza.
D. Helyi sajtossgok 1231
A konstruktort gy adhatjuk meg:
Da..Da(!u uu, Mou uu, !u ,,, !u ua,_oJ_u;
. u(uu;, u(uu;, ,(,,;
{
!J (uU && uMou(U; && ,U; :n:u, Da(U,U,U; a un!! unu
!J (uuau '' uuu; :ou 1au_ua(:o::z a ouap;,
!J (uuI '' Iuu; o:u !g,:z:n:::, !:u IUI
:ou 1au_ua(:o::z a ouap uapa;,
!J (ua,_oJ_u && ua,_!u_u(,,,uu,uu;:ua,_oJ_u;
:ou 1au_ua(:o::z a uapa;,
}
Da..Da(; . u(U;, u(U;, ,(U; { } g, un!! unu
A ua,_!u_u(; kiszmtsa nem knny s nem kapcsoldik a loklokhoz, ezrt kihagy-
tam. Ha szksgnk van r, rendszernkben biztosan megtallhatjuk valahol.
Az sszehasonlt mveletek mindig hasznosak az olyan tpusok esetben, mint a Da:
oo! op:ao:(ou: Da& ., ou: Da& ,;
{
:n:u .,a:(;,,a:(; && .uou(;,uou(; && .ua,(;,ua,(;,
}
oo! op:ao::(ou: Da& ., ou: Da& ,;
{
:n:u :(.,;,
}
Mivel eltrtnk a szabvnyos u s !u_ formtumoktl, szksgnk van konverzis
fggvnyekre is, amelyek egytt tudnak mkdni azokkal a programokkal, amelyek eze-
ket a tpusokat vrjk el:
:o!u Da..ua_u(u* p; ou: a unu *p- !,z:
{
u . { U },
*p .,
p->u_,a: ,-IUUU,
p->u_uua, u,
p->u_uou u-I,
}
!u_ Da..ua_!u_(; ou:
{
!J (,IU7U '' 2U3,; !g,:z:n::
Fggelkek s trgymutat 1232
:ou 1au_ua( unu a !u_ a:ouu,u ::n! :!;,
u .,
ua_u(&.;,
:n:u u!u(&.;,
}
D.4.4.6. Dtumformtumok megadsa
A C++ nem hatrozza meg a dtumok kirsnak szabvnyos formtumt (a %. kzelti meg
a legjobban; D.4.4.3), de mg ha ltezne is ilyen, valsznleg szeretnnk ms formtumo-
kat is hasznlni. Ezt gy tehetjk meg, hogy meghatrozunk egy alaprtelmezett formtu-
mot s lehetsget adunk annak mdostsra:
!a:: Da_Jo:ua {
:a! a: Ju/], a!ap:!uz Jo:unu
ou: a:* n::, az ppu ::u,: Jo:unu
ou: a:* n::_uu,
pn!!.
Da_Jo:ua(; . n::(Ju;, n::_uu(Ju-::!u(Ju;; { }
ou: a:* g!u(; ou: { :n:u n::, }
ou: a:* uu(; ou: { :n:u n::_uu, }
:o!u :(ou: a:* p, ou: a:* ; { n::p, n::_uu, }
:o!u :(ou: a:* p; { n::p, n::_uun::-::!u(p;, }
:a! ou: a:* uJan!_Ju(; { :n:u Ju, }
},
ou: a: Da_Jo:uaa:>..Ju/] %, %1 %u, %, p! 1:!ua,, 1:na:, 5, IUUU
Da_Jo:ua ua_Ju,
Hogy az ::J!u(; formtumot (D.4.4.3) hasznlhassuk, tartzkodtam attl, hogy
a Da_Jo:ua osztlyt a hasznlt karaktertpussal paramterezzem. Ebbl kvetkezik, hogy
ez a megolds csak olyan dtumjellst enged meg, amelynek formtumt ki lehet fejezni
a a:/] tpussal. Ezenkvl felhasznltam egy globlis formtum-objektumot is (ua_Ju),
az alaprtelmezett dtumformtum megadshoz. Mivel a ua_Ju rtkt meg lehet vltoz-
tatni, a Da formzshoz rendelkezsnkre ll egy meglehetsen nyers mdszer, ha-
sonlan ahhoz, ahogy a g!oa!(; loklt (D.2.3) lehet hasznlni a formzsra.
D. Helyi sajtossgok 1233
Sokkal ltalnosabb megolds, ha ltrehozzuk a Da_!u s Da_on Ja-eket az adatfo-
lyambl trtn olvass s rs vezrlshez. Ezt a megkzeltst a D.4.4.7 pontban mutat-
juk be. Ha adott a Da_Jo:ua, a Da..op:ao:(;-t gy rhatjuk meg:
up!a!a:: , !a:: T:>
a:!_o::au,T:>& op:ao:(a:!_o::au,T:>& :, ou: Da& u;
::: J!a:zu!o! Jo:unuua!
{
,puau a:!_o::au,T:>..:u:, gna:u(:;, !:u 2I3
!J (:gna:u; :n:u :,
u ,
uua_u(&;,
:, {
ou: !u_pn>& J n:_Ja !u_pn> >(:g!o(;;,
!J (Jpn(:,:,:J!!!(;,&,ua_Jug!u(;,ua_Juuu(;;Ja!!u(;;
:::a(!o:_a:..Ja!!!;,
}
a (; {
auu!_!o.p!ou(:;, !:u D422
}
:n:u :,
}
A a:_Ja fggvnnyel ellenrizhetnnk, hogy az : loklja rendelkezik-e a !u_pn>
jellemzvel, itt azonban egyszerbb gy kezelni a problmt, hogy minden kivtelt elka-
punk, amit a n:_Ja kivlt.
me egy egyszer tesztprogram, ami a kimenet formtumt a ua_Ju-n keresztl vezrli:
!u ua!u(;
:, {
u!! (!u >> uu && uu : Da(;; on uu uu!, ::: az a!ap:!uz
ua_Ju a:zu!a:a!
ua_Ju:(%%u%u;,
u!! (!u >> uu && uu : Da(;; on uu uu!, ::: az %%u%u
a:zu!a:a!
}
a (Da..1au_ua ; {
on Ro::z unu. u, uu!,
}
Fggelkek s trgymutat 1234
D.4.4.7. Bemeneti facet-ek dtumokhoz
Mint mindig, a bemenet kezelse kicsit nehezebb, mint a kimenet. Mgis, mivel
a g_ua(; javtott a felleten az alacsonyszint bemenethez s mert a D.4.4.4 pontban
a Da tpushoz megadott op:ao:>>(; nem frt hozz kzvetlen mdon a Da brzol-
shoz, az op:ao:>>(;-t vltozatlanul hasznlhatjuk. me az op:ao:>>(; sablon fggvny-
knt megrt vltozata:
up!a!a:: , !a:: T:>
!::au,T:>& op:ao:>>(!::au,T:>& :, Da& u;
{
,puau !::au,T:>..:u:, gna:u(:;,
!J (gna:u; :, {
!o:_a:..!o:a :: U,
u . { U },
!::aunJ_!:ao:,T:> uu,
n:_Ja !u_g> >(:g!o(;;g_ua(:,uu,:,::,&.;,
!J (::U '' ::!o:_a:..oJ!;
u Da(.u_uua,,Da..Mou(.u_uou-I;,.u_,a:-IUUU,.u_uua,;,
!:
:::a(::;,
}
a (; {
auu!_!o.p!ou(:;, !:u D422
}
:n:u :,
}
Ez a bemeneti mvelet az !::au !u_g jellemzjnek g_ua(; fggvnyt hvja meg,
gy a bemenet j, rugalmasabb formjt adhatjuk meg, gy, hogy szrmaztatssal egy j
Ja-et ksztnk a !u_g-bl:
up!a!a:: , !a:: 1u !::aunJ_!:ao:> >
!a:: Da_!u . pn!! :u..!u_g,1u> {
pn!!.
Da_!u(:!z_ : U; . :u..!u_g>(:; { }
p:ou.
1u uo_g_ua(1u , 1u , !o:_a:& :, !o:_a:..!o:a& :, u* up; ou:,
p:!:a.
unu !,p { uo:a!n, nuuouu, ua,oJu, uou },
1u g:a!(1u , 1u , !o:_a:& :, !o:_a:..!o:a& :, !u* :, !,p* ::; ou:,
},
D. Helyi sajtossgok 1235
A g:a!(; fggvnynek egy vet, egy hnapot, a hnap napjt s a ht egy napjt kell be-
olvasnia (ez utbbi nem ktelez), az eredmnyt pedig egy u szerkezetbe kell tennie.
A hnapok s a ht napjainak nevei a lokltl fggnek, kvetkezskppen nem emlthet-
jk meg azokat kzvetlenl a bemeneti fggvnyben. Ehelyett a hnapokat s napokat gy
ismerjk fel, hogy meghvjuk azokat a fggvnyeket, amelyeket a !u_g ad erre a clra:
a g_uouuau(; s g_uua,(; fggvnyeket (D.4.4.4).
Az v, a hnap napja s valsznleg a hnap is egszknt van brzolva. Sajnos egy szm
nem jelzi, hogy egy hnap napjt jelli-e vagy valami egszen mst. A 7 pldul jellhet j-
liust, egy hnap 7. napjt vagy ppen a 2007-es vet is. A !u_g ua_o:u:(; fggvny-
nek valdi clja az, hogy feloldja az effle tbbrtelmsgeket.
A Da_!u rtkeket olvas be, osztlyozza azokat, majd a ua_o:u:(; fggvnnyel megn-
zi, a bert adatok rtelmesek-e (illetve hogyan rtelmesek). A tnyleges olvasst az adat-
folyam tmeneti trbl, illetve a kezdeti osztlyozst a privt g:a!(; fggvny vgzi:
up!a!a:: , !a:: 1u>
1u Da_!u,1u>..g:a!(1u ,1u ,!o:_a:& :,!o:_a:..!o:a& :,!u* :,!,p* ::;
ou:
Da ::zu o!:a::a. :zu, a uapa :ag, ouap ::!, : :::! !p:
{
ou: ,p>& n:_Ja ,p> >(:g!o(;;, a ,p !:::
!:u D45-u
,
*:: uo:a!n, uu a!! :
Jo: (,,; { n::!, : :::! !p:
!J ( ; :n:u ,
*,
!J (:(!:(,p_a:..:pa,; '' !:(,p_a:..pnu,;;; :a,
--,
}
!J (!:(,p_a:..u!g!,;; { g:z o!:a::a a unupnu J!g,!uu ::n! ag,::a!
!u ! U,
uo { :zo!g: a:a::z! :zug,u u!u!!: : a!a::a
:a! a: ou: u!g!:/] UI245o73U,
! !*IU - J!uu(u!g!:,u!g!:-IU,ua::ou(, ;;-u!g!:,
*--,
} u!! (!:(,p_a:..u!g!,;;,
*: !,
Fggelkek s trgymutat 1236
*:: nuuouu, g, g:z, u uu nun, u! :zo!
:n:u ,
}
!J (!:(,p_a:..a!pa,;; { ouap u:u :ag, a uapua :::
a:!_::!ug> ::,
u!! (!:(,p_a:..a!pa,;; { a:a: o!:a::a a:a:!ua
:: - ,
!J (-- ; :a,
*,
}
u ,
a:!_::!ug::au> ::(::;,
,puJ !::aunJ_!:ao:> S1, :o:pn: az :: uu! :oz
g_uouuau(:::unJ(;,S1(;,:,:,&;, o!:a:: uuo:!a!! auaJo!,au
uu! :o!
!J ((:&(!o:_a:..au!'!o:_a:..Ja!!!;;U; {
*: u_uou,
*:: uou,
:n:u ,
}
: U, az auaJo!,au-!!apo o:!: a u:ou! o!:a:: !o
g_uua,(:::unJ(;,S1(;,:,:,&;, o!:a:: uuo:!a!! auaJo!,au
uu! :o!
!J ((:&(!o:_a:..au!'!o:_a:..Ja!!!;;U; {
*: u_uua,,
*:: ua,oJu,
:n:u ,
}
}
: ' !o:_a:..Ja!!!,
:n:u ,
}
Itt a trkks rsz a ht napjainak s a hnapoknak a megklnbztetse. Mivel bemene-
ti bejrkon keresztl olvasunk, nem olvashatjuk be /,;-t ktszer, elszr egy hnapot,
msodszor pedig egy napot keresve. Msfell nem tudjuk megklnbztetni a hnapokat
sem a napoktl, ha egyszerre csak egy karaktert olvasunk be, mert csak
a g_uouuau(; s a g_uua,(; fggvnyek tudjk, hogy az adott loklban a hna-
pok s a ht napjainak nevei mely karaktersorozatokbl plnek fel. Azt a megoldst v-
lasztottam, hogy az alfabetikus karakterekbl ll sorozatokat beolvastam egy karakterlnc-
ba, ebbl egy ::!ug::au-et ksztettem, majd ismtelten olvastam az adatfolyam
::aunJ-jbl.
D. Helyi sajtossgok 1237
A hibajelz rendszer kzvetlenl hasznlja az olyan llapotbiteket, mint az !o:_a:..au!.
Ez azrt szksges, mert az adatfolyam llapott kezel knyelmesebb fggvnyeket, mint
a !a:(; s a ::a(;, a a:!_!o: osztly hatrozza meg, nem pedig annak bzisosztlya,
az !o:_a: (21.3.3). Ha szksges, a >> opertor felhasznlja a g_ua(; ltal jelentett hi-
bkat, hogy visszalltsa a bemeneti adatfolyam llapott.
Ha a g:a!(; adott, elszr beolvashatjuk az rtkeket, majd ksbb megnzhetjk, hogy
rtelmesek-e. A uao:u:(; szerepe dnt lehet:
up!a!a:: , !a:: 1u>
1u Da_!u,1u>..uo_g_ua(1u , 1u , !o:_a:& :, !o:_a:..!o:a& :, u* up; ou:
a uapa (uu o!zo;, u!, uu, uu,, uu,, :ag, ,uu Jo:unu o:
{
!u :a!/], uap, ouap, : : : :zu:a
!,p ::/] { uo:a!n }, :o:z!,oz:oz
Jo: (!u !U, : && !, --!; { uap, ouap, : o!:a::a
g:a!(,,:,:,&:a!/!],&::/!];,
!J (:; :n:u , opp. !a
!J (::/!]uo:a!n; { uu nun Jzu! a unuo
: ' !o:_a:..au!,
:n:u ,
}
!J (::/!]ua,oJu; {
up->u_uua, :a!/!],
--!, opp. uu uap, ouap, :ag, :
}
}
!u_a:..uao:u: o:u: uao:u:(;, uo: ugp:o!nu :ouu!
a o!:a:o aua !u::
!J (::/U] uou; { uu, Jo:unu :ag, !a
}
!: !J (::/I] uou; { uu, :ag, ,uu :ag, !a
up->u_uou :a!/I],
:u! (o:u:;
{
a: uu,.
up->u_uua, :a!/U],
up->u_,a: :a!/2],
:a,
a: ,uu.
up->u_,a: :a!/U],
up->u_uua, :a!/I],
Fggelkek s trgymutat 1238
:a,
uJan!.
: ' !o:_a:..au!,
:n:u ,
}
}
!: !J (::/2] uou; { ,uu :ag, !a
}
!: { ug:znu a uao:u:-u :ag, !a
}
up->u_,a: - IUUU, az a!ap: !gaz::a a u-z
:n:u ,
}
Azokat a kdrszleteket, amelyek nem jrulnak hozz a loklok, dtumok s a bemenet ke-
zelsnek megrtshez, kihagytam. A jobb s ltalnosabb dtumformtumok beolvass-
ra alkalmas fggvnyek megrst feladatknt tztem ki (D.6[9-10]).
me egy egyszer tesztprogram:
!u ua!u(;
:, {
!u!un(!o(!oa!(;, uu Da_!u;;, unuo o!:a::a a Da_!u a:zu!a:a!
u!! (!u >> uu && uu : Da(;; on uu uu!,
}
a (Da..1au_ua ; {
on Ro::z unu. u, uu!,
}
Vegyk szre, hogy a uo_g_ua(; rtelmetlen dtumokat is elfogad, mint amilyen a
Tn::ua, Oo: 7, IUU3
s az
IUUU1I
Az v, hnap, nap s (nem ktelezen) a ht napja egysgessgnek ellenrzse a Da
konstruktorban trtnik. A Da osztlynak kell tudnia, mi alkot helyes dtumot, a Da_!u
osztllyal pedig nem kell megosztania ezt a tudst.
D. Helyi sajtossgok 1239
Meg lehetne oldani azt is, hogy a g_:a!(; vagy a g_ua(; fggvnyek prbljk kitall-
ni a szmrtkek jelentst. Pldul a
I2 Ma, IU22
vilgos, hogy nem a 12-es v 1922. napja. Azaz gyanthatnnk, hogy egy olyan szmrtk,
ami nem lehet a megadott hnap napja, biztosan vet jell. Az ilyen feltevsek bizonyos
esetekben hasznosak lehetnek, de nem j tlet ezeket ltalnosabb krnyezetben hasznl-
ni. Pldul a
I2 Ma, I5
a 12., 15., 1912.,1915., 2012., vagy 2015. vben jellhet egy dtumot. Nha jobb megkze-
lts, ha kiegsztjk a jellst valamivel, ami segt az vek s napok megklnbztets-
ben. Az angolban a I
:
s I5
!!o
:!:z!
>>>
!gu
uu
a!u
>>>
a program a kvetkezt rja ki:
!!o
a!u
Mg!u :::
Mg!u :::
D.4.7.1. Ms facet-ekben lv zenetek hasznlata
Azon tl, hogy a felhasznlkkal val kapcsolattartsra alkalmas loklfgg karakterlnco-
kat trolnak, az zenetek arra is felhasznlhatk, hogy ms Ja-ek szmra troljanak ka-
rakterlncokat. A Sa:ou_!o jellemzt (D.3.2) pldul gy is megrhattuk volna:
!a:: Sa:ou_!o . pn!! !oa!..Ja {
ou: u::ag:a:>& u, nzuou,::
!u a, nzuaa!ogn:
pn!!.
!a:: M!::!ug_u::ag: { },
Sa:ou_!o(!u ! U;
. !oa!..Ja(!;,
u(n:_JaSa:ou_u::ag:>(!oa!(;;;,
a(uopu(u::ag_u!:o:,,!oa!(;;;
{ !J (aU; :ou M!::!ug_u::ag:(;, }
-Sa:ou_!o(; { } !o: :z! a Sa:ou_!o onuo J!:zuo!: (D;
ou: ::!ug& o_::(Sa:ou .; ou:, . :zo!:a a:a:!ua!
oo! J:ou_::(ou: ::!ug& :, Sa:ou& .; ou:, az :-u ugJ!!o
Sa:ou onuo .- !,z!
Fggelkek s trgymutat 1254
:a! !oa!..!u !u, Ja-azouo::o onu (D2, D, DI;
},
!oa!..!u Sa:ou_!o..!u, az azouo::o onu uga:oz:a
ou: ::!ug& Sa:ou_!o..o_::(Sa:ou .; ou:
{
:n:u u->g(a, ., N!u: !!,u ::za;,
}
oo! Sa:ou_!o..J:ou_::(ou: ::!ug& :, Sa:ou& .; ou:
{
Jo: (!u ! Sa:ou..:p:!ug, !Sa:ou..u!u:, !--;
!J (u->g(a, !, N!u: !!,u ::za; :; {
. Sa:ou(!;,
:n:u :n,
}
:n:u Ja!:,
}
Ez az zenetekre pl megolds abban klnbzik az eredetitl (D.3.2), hogy a Sa:ou
karakterlncok halmazt egy adott loklhoz megr programoznak a karakterlncokat
hozz kell tudnia adni egy u::ag: knyvtrhoz. Ezt az teheti meg knnyen, aki j loklt
ad a vgrehajtsi krnyezethez. Mgis, mivel a u::ag: csak olvashat felletet nyjt, az
vszakok egy jabb halmaznak megadsa a rendszerprogramozk hatskrn kvl esik.
A u::ag: _,uau vltozata (D.4, D.4.1) is adott:
up!a !a:: >
!a:: :u..u::ag:_,uau . pn!! u::ag:> { * * },
D.5. Tancsok
[1] Szmtsunk r, hogy a felhasznlkkal kzvetlenl trsalg programokat s
rendszereket tbb orszgban is hasznlni fogjk. D.1.
[2] Ne ttelezzk fel, hogy mindenki ugyanazt a karakterkszletet hasznlja, amit
mi. D.4.1.
[3] Ha a bemenet s kimenet fgg a helyi sajtossgoktl, loklokat hasznljuk s
ne alkalmi kdot rjunk. D.1.
[4] Kerljk a loklnevek begyazst a programszvegbe. D.2.1.
D. Helyi sajtossgok 1255
[5] Hasznljuk a lehet legkevesebb globlis formzst. D.2.3, D.4.4.7.
[6] Rszestsk elnyben a loklhoz igazod karakterlnc-sszehasonltsokat s -
rendezseket. D.2.4, D.4.1.
[7] A Ja-ek legyenek nem mdosthatk. D.2.2, D.3.
[8] Csak kevs helyen vltoztassuk meg a loklt egy programban. D.2.3.
[9] Hagyjuk, hogy a lokl szablyozza a Ja-ek lettartamt. D.3.
[10] Amikor loklfgg I/O fggvnyeket runk, ne felejtsk el kezelni a felhaszn-
li (fellrt) fggvnyek okozta kivteleket. D.4.2.2.
[11] A pnzrtkek trolsra hasznljunk egy egyszer Mou, tpust. D.4.3.
[12] Hasznljunk egyszer felhasznli tpusokat az olyan rtkek trolsra, ame-
lyek lokltl fgg I/O-t ignyelnek (s ne a beptett tpusok rtkeit alaktsuk
oda-vissza). D.4.3.
[13] Ne higgynk az idrtkeknek, amg nincs valamilyen j mdszernk arra,
hogy beleszmtsuk az sszes lehetsges mdost tnyezt. D.4.4.1.
[14] Legynk tisztban a !u_ tpus korltaival. D.4.4.1, D.4.4.5.
[15] Hasznljunk olyan dtumbeviteli eljrst, amely tbbfle formtumot is elfogad.
D.4.4.5.
[16] Rszestsk elnyben az olyan karakterosztlyoz fggvnyeket, amelyekben
a lokl kifejezetten megadott. D.4.5, D.4.5.1.
D.6. Gyakorlatok
1. (*2,5) Ksztsk el a Sa:ou_!o-t (D.3.2) az amerikai angoltl eltr nyelvre.
2. (*2) Hozzunk ltre egy Sa:ou_!o osztlyt (D.3.2), amelynek konstruktora ne-
vek halmazt veszi paramterknt, hogy a klnbz loklokban lv vszakok
neveit ezen osztly objektumaiknt lehessen brzolni.
3. (*3) rjunk egy o!!aa:>..oupa: fggvnyt, amely bcsorrendet llt
fel. Lehetleg olyan nyelvre ksztsk el, mint a nmet, a francia vagy a magyar,
mert ezek bcje az angolnl tbb bett tartalmaz.
4. (*2) rjunk egy programot, ami logikai rtkeket szmokknt, angol szavakknt
s egy tetszleges nyelv szavaiknt olvas be s r ki.
5. (*2,5) Hatrozzuk meg a T!u tpust a pontos id brzolsra. Hatrozzuk
meg a Da_auu_!u tpust is, a T!u s valamilyen Da tpus felhasznls-
val. Fejtsk ki ennek a megkzeltsnek a D.4.4. pontban szerepl Da tpus-
sal szembeni elnyeit s htrnyait. rjuk meg a T!u s a Da_auu_!u tpu-
sok loklfgg be- s kimeneti eljrsait.
Fggelkek s trgymutat 1256
6. (*2,5) Tervezznk meg s ksztsnk el egy postai irnytszm Ja-et. rjuk
meg legalbb kt, eltr cmzsi szoksokat hasznl orszgra.
7. (*2,5) Ksztsnk egy telefonszm Ja-et. rjuk meg legalbb kt, eltr tele-
fonszm-formt (pldul (973) 360-8000 s 1223 343000) hasznl orszgra.
8. (*2,5) Prbljuk meg kitallni, milyen be- s kimeneti formtumokat hasznl
C++-vltozatunk a dtumokhoz.
9. (*2,5) rjunk olyan g_!u(; fggvnyt, amely megprblja kitallni a tbbr-
telm dtumok pldul a I2U5IUU5 jelentst, de elutast minden vagy
majdnem minden hibt. Hatrozzuk meg pontosan, melyik tallgatst fogad-
juk el s gondoljuk t a hibk valsznsgt.
10. (*2) rjunk olyan g_!u(; fggvnyt, ami tbbfajta bemeneti formtumot fo-
gad el, mint a D.4.4.5 pontban szerepl vltozat.
11. (*2) Ksztsnk listt a rendszernk ltal tmogatott loklokrl.
12. (*2,5) Talljuk meg, rendszernk hol trolja a nevestett loklokat. Ha van hoz-
zfrsnk a rendszer azon rszhez, ahol a loklok troldnak, ksztsnk egy
j, nvvel rendelkez !oa!-t. Legynk vatosak, nehogy tnkretegyk a mr
ltez !oa!-eket.
13. (*2) Hasonltsuk ssze a Sa:ou_!o kt megvalstst (D.3.2 s D.4.7.1).
14. (*2) rjuk meg, s teszteljk le a Da_on Ja-et, ami Da-eket r ki
a konstruktornak megadott paramter ltal meghatrozott formban. Fejtsk ki
ennek a megkzeltsnek az elnyeit s htrnyait a ua_Ju ltal nyjtott glo-
blis adatformtummal (D.4.4.6) szemben.
15. (*2,5) rjuk meg a rmai szmok (pldul A1 s MD111) be- s kimeneti
eljrsait.
16. (*2,5) Ksztsk el s ellenrizzk a :_o_npp:-t (D.4.6).
17. (*2,5) llaptsuk meg a kvetkezk tlagos kltsgt a !o(; fggvny felhasz-
nlsval: (1) fggvnyhvs, (2) virtulis fggvnyhvs, (3) egy a: beolvas-
sa, (4) egy 1 szmjegy !u beolvassa, (5) egy 5 szmjegy !u beolvassa (6)
egy 5 szmjegy uon!, (7) egy 1 karakteres ::!ug, (8) egy 5 karakteres ::!ug,
s (9) egy 40 karakteres ::!ug beolvassa.
18. (*6,5) Tanuljunk meg egy msik termszetes nyelvet.
D. Helyi sajtossgok 1257
Kivtelbiztossg a standard knyvtrban
Minden gy mkdik, ahogy
elvrjuk feltve, hogy
elvrsaink helyesek.
(Hyman Rosen)
Kivtelbiztossg Kivtelbiztos eljrsok Erforrsok brzolsa rtkads
push_back() Konstruktorok s invarinsok A szabvnyos trolk szolgltatsai Ele-
mek beillesztse s eltvoltsa Garancik s kompromisszumok swap() A kezdeti r-
tkads s a bejrk Hivatkozs elemekre Prediktumok Karakterlncok, adatfolya-
mok, algoritmusok, a valarray s a complex A C standard knyvtra Javaslatok
a knyvtrak felhasznli szmra Tancsok Gyakorlatok
E.1. Bevezets
A standard knyvtr fggvnyei gyakran olyan fggvnyeket hvnak meg, melyeket a fel-
hasznl ad meg akr fggvny-, akr sablonparamterek formjban. Termszetesen ezek
a felhasznli eljrsok nha kivteleket vltanak ki. Egyes fggvnyek (pldul a mem-
riafoglal eljrsok) nmagukban is kpesek kivtel kivltsra:
E
void f(vector<X>& v, const X& g)
{
v[2] = g; // X tpus rtkadsa kivtelt vlthat ki
v.push_back(g); // vector<X> memriafoglalja kivtelt vlthat ki
sort(v.begin(), v.end()); // X "kisebb mint" opertora kivtelt vlthat ki
vector<X> u = v; // X msol konstruktora kivtelt vlthat ki
// ...
// u itt semmisl meg: biztostanunk kell, hogy X destruktora helyesen mkdjn
}
Mi trtnik, ha az rtkads kivtelt vlt ki, mikzben a g rtkt prbljuk lemsolni? A v
ezutn egy rvnytelen elemet fog tartalmazni? Mi trtnik, ha az a konstruktor, amit
a v.push_back() hasznl a g lemsolshoz, std::bad_alloc kivtelt vlt ki? Megvltozik az
elemek szma? Bekerlhet rvnytelen elem a trolba? Mi trtnik, ha az X osztly kisebb,
mint opertora eredmnyez kivtelt a rendezs kzben? Az elemek ezutn rszben rende-
zettekk vlnak? Elkpzelhet, hogy a rendez eljrs eltvolt egy elemet a trolbl s
egy hiba miatt nem teszi vissza?
A fenti pldban szerepl sszes kivtel-lehetsg megtallsa az E.8.[1] feladat clja, ezen
fggelk az, hogy elmagyarzzuk, hogyan illik viselkednie a fenti programnak az sszes
megfelelen meghatrozott X tpus esetben (belertve azt az esetet is, amikor az X kivtele-
ket vlthat ki). Termszetesen a fggelk nagy rszben azt fogjuk tisztzni, mit is neveznk
helyes viselkedsnek, illetve megfelelen meghatrozottnak a kivtelekkel kapcsolatban.
A fggelkben a kvetkezkkel foglalkozunk:
1. Megvizsgljuk, hogyan adhat meg a felhasznl olyan tpusokat, amelyek meg-
felelnek a standard knyvtr elvrsainak.
2. Rgztjk, milyen garancikat biztost a standard knyvtr.
3. Megnzzk, milyen elvrsokat llt a standard knyvtr a felhasznl ltal
megadott programrszekkel szemben.
4. Bemutatunk nhny hatkony mdszert, mellyel kivtelbiztos s hatkony tro-
lkat kszthetnk.
5. Megemltjk a kivtelbiztos programozs nhny ltalnos szablyt.
A kivtelbiztossg vizsglata rtelemszeren a legrosszabb esetben tapasztalhat viselke-
dssel foglalkozik. Hol jelentheti egy kivtel a legtbb problmt? Hogyan tudja a standard
knyvtr megvdeni magt s a felhasznlt a lehetsges problmktl? Hogyan segthet
a felhasznl a problmk elkerlsben? Ne hagyjuk, hogy az itt bemutatott kivtel-
Fggelkek s trgymutat 1260
kezelsi mdszerek elfeledtessk velnk, hogy a kivtelek kivltsa a legjobb mdszer a hi-
bk jelzsre (14.1, 14.9). Az elveket, a mdszereket s a standard knyvtr szolgltatsa-
it a kvetkez rendszerben trgyaljuk:
E.2. Ebben a pontban a kivtelbiztossg fogalmt vizsgljuk meg.
E.3. Itt mdszereket mutatunk arra, hogyan rhatunk hatkony, kivtelbiztos
trolkat s mveleteket.
E.4. Ebben a rszben krvonalazzuk a standard knyvtr troli s mveletei
ltal biztostott garancikat.
E.5. Itt sszefoglaljuk a kivtelbiztossg problmjt a standard knyvtr nem
trolkkal foglalkoz rszben.
E.6. Vgl jbl ttekintjk a kivtelbiztossg krdst a standard knyvtr
felhasznlinak szemszgbl.
Szoks szerint a standard knyvtr pldkat mutat azokra a problmatpusokra, amelyekre
egy alkalmazs fejlesztsekor oda kell figyelnnk. A standard knyvtrban a kivtelbiztos-
sg megvalstsra alkalmazott eljrsok szmos ms terleten is felhasznlhatk.
E.2. Kivtelbiztossg
Egy objektumon vgrehajtott mveletet akkor neveznk kivtelbiztosnak, ha a mvelet az
objektumot akkor is rvnyes llapotban hagyja, ha kivtel kivltsval rt vget. Ez az r-
vnyes llapot lehet egy hiballapot is, amit esetleg csak teljes jbli ltrehozssal lehet
megszntetni, de mindenkppen pontosan meghatrozottnak kell lennie, hogy az objek-
tumhoz logikus hibakezel eljrst adhassunk meg. A kivtelkezel pldul trlheti az ob-
jektumot, kijavthatja azt, megprblkozhat a mvelet egy msik vltozatval vagy megpr-
blhat egyszeren tovbbhaladni a hiba figyelmen kvl hagysval.
Ms szavakkal, az objektum rendelkezni fog egy invarinssal (llapotbiztost, nem vlto-
z llapot 24.3.7.1), melyet konstruktorai lltanak el, s minden tovbbi mveletnek meg
tartania az ltala lert llapotot, mg akkor is, ha kivtelek kvetkeztek be. A vgs rendra-
kst a destruktorok vgzik el. Minden mveletnek figyelnie kell arra, hogy a kivtelek ki-
vltsa eltt visszalltsk az invarinst, hogy az objektum rvnyes llapotban lpjen ki
a mveletbl. Termszetesen nagy valsznsggel ez az rvnyes llapot nem az az lla-
pot lesz, amire az alkalmazsnak ppen szksge lenne. Egy karakterlnc egy kivtel k-
vetkeztben pldul ress vlhat, egy trol pedig rendezetlen maradhat. Teht a kijav-
E. Kivtelbiztossg a standard knyvtrban 1261
ts csak azt jelenti, hogy az objektumnak olyan rtket adunk, ami elfogadhatbb a prog-
ram szmra, mint az, amit a flbeszakadt mvelet benne hagyott. A standard knyvtr
szempontjbl a legrdekesebb objektumok a trolk.
Az albbiakban azt vizsgljuk meg, milyen felttelek mellett nevezhetjk a szabvnyos t-
rolkat feldolgoz mveleteket kivtelbiztosnak. Elvileg mindssze kt egyszer megkze-
lts kzl vlaszthatunk:
1. Nincs biztosts: Ha kivtel lp fel, a mvelet ltal hasznlt valamennyi trolt
valsznleg srltnek ttelezzk fel.
2. Ers biztosts: Ha kivtel lp fel, minden trol pontosan abba az llapotba ke-
rl vissza, mint amiben a standard knyvtr mveletnek megkezdse eltt volt.
Sajnos ez a kt megolds annyira egyszer, hogy igazn nem is alkalmazhat. Az els azrt
elfogadhatatlan, mert ha ezen megolds mellett egy trolmvelet kivtelt vlt ki, a trolt
tbbet nem rhetjk el, st mg nem is trlhetjk anlkl, hogy futsi idej hibktl kne
rettegnnk. A msodik lehetsg azrt nem hasznlhat, mert ekkor a visszallts megva-
lstsnak kltsgei a standard knyvtr minden mveletben jelentkeznnek.
A problma megoldsra a C++ standard knyvtra kivtelbiztostsi szinteket knl, me-
lyek a helyes program ksztsnek terheit megosztjk a standard knyvtr megvalsti s
felhasznli kztt:
3a Alapbiztosts az sszes mveletre: A standard knyvtr alapvet invarinsai
mindenkppen fennmaradnak s semmilyen erforrs (pldul memriatarto-
mny) nem maradhat lefoglalt.
3b Ers biztosts a legfontosabb mveletekhez: Az alapbiztostson tl, a mvelet
vagy sikeresen vgrehajtsra kerl, vagy semmilyen vltozst nem eredmnyez.
Ilyen szint biztosts csak a knyvtr legfontosabb mveleteit illeti meg, pld-
ul a push_back(),a list osztlyban az egyelem insert(), illetve az
uninitialized_copy() fggvnyeket (E.3.1, E.4.1).
3c Nncs kivtel biztosts bizonyos mveletekre Az alapbiztosts mellett nhny
mvelet egyltaln nem vlthat ki kivteleket. Ez a tpus biztosts csak n-
hny egyszer mveletre valsthat meg, pldul a swap() vagy a pop_back()
fggvnyre (E.4.1).
Az alapbiztosts s az ers biztosts is felttelezi, hogy a felhasznl ltal megadott mve-
letek (pldul az rtkadsok s a swap() fggvnyek) nem hagyjk a trol elemeit r-
vnytelen llapotban s minden ltaluk lefoglalt erforrst felszabadtanak. Ezenkvl
a destruktoroknak nem szabad kivtelt kivltaniuk. Pldul vizsgljuk meg az albbi oszt-
lyokat (25.7):
Fggelkek s trgymutat 1262
template<class T> class Safe {
T* p; // p egy T tpus, new-val lefoglalt objektumra mutat
public:
Safe() : p(new T) { }
~Safe() { delete p; }
Safe& operator=(const Safe& a) { *p = *a.p; return *this; }
// ...
};
template<class T> class Unsafe { // hanyag s veszlyes kd
T* p; // egy T-re mutat
public:
Unsafe(T* pp) : p(pp) { }
~Unsafe() { if (!p->destructible()) throw E(); delete p; }
Unsafe& operator=(const Unsafe& a)
{
p->~T(); // a rgi rtk trlse (10.4.11)
new(p) T(a.p); // T ltrehozsa *p-ben a.p alapjn (10.4.11)
return *this;
}
// ...
};
void f(vector< Safe<Some_type> >&vg, vector< Unsafe<Some_type> >&vb)
{
vg.at(1) = Safe<Some_type>();
vb.at(1) = Unsafe<Some_type>(new Some_type);
// ...
}
Ebben a pldban a Safe osztly ltrehozsa csak akkor sikeres, ha a T osztly is sikeresen
ltrejn. Egy T objektum ltrehozsa meghisulhat azrt, mert nem sikerl a memriafog-
lals (ilyenkor std::bad_alloc kivtel jelentkezik), vagy azrt, mert a T konstruktora brmi-
lyen okbl kivtelt vlt ki. Ettl fggetlenl, egy sikeresen ltrehozott Safe esetben a p egy
hibtlan T objektumra mutat, mg ha a konstruktor sikertelen, sem T, sem Safe objektum
nem jn ltre. Ugyangy kivtelt vlthat ki a T rtkad mvelete is; ekkor a Safe rtkad
mvelete (a C++ mkdsnek megfelelen) tovbbdobja a kivtelt. Mindez nem jelent
problmt mindaddig, amg a T rtkad opertora sajt operandust megfelel llapotban
hagyja. Teht a Safe kvetelmnyeinknek megfelelen mkdik, gy a standard knyvtr
mveletei Safe objektumokra alkalmazva logikus s megfelelen meghatrozott eredmnyt
fognak adni.
E. Kivtelbiztossg a standard knyvtrban 1263
Ezzel szemben az Unsafe() konstruktort figyelmetlenl rtuk meg (pontosabban figyelme-
sen gy rtuk meg, hogy a helytelen formt bemutassa). Egy Unsafe objektum ltrehozsa
sohasem fog meghisulni. Ehelyett az objektumot hasznl mveletekre (pldul az rtk-
adsra s a megsemmistsre) bzzuk, hogy trdjenek sajt beltsuk szerint az sszes le-
hetsges problmval. Az rtkads meghisulhat gy, hogy a T msol konstruktora kivlt
egy kivtelt. Ilyenkor a T tpus objektumot nem meghatrozott llapotban hagyjuk, hiszen
a *p rgi rtkt trltk, de nem helyettestettk rvnyes rtkkel. Az ilyen mkds k-
vetkezmnyei ltalban megjsolhatatlanok. Az Unsafe destruktora tartalmaz egy remny-
telen prblkozst az rvnytelen megsemmists elkerlsre, egy kivtel meghvsa egy
msik kivtel kezelse kzben azonban a terminate() (14.7) meghvst eredmnyezi, mg
a standard knyvtr elvrja, hogy a destruktor szablyosan visszatrjen az objektum trlse
utn. A standard knyvtr nem kszlt fel s nem is tud felkszlni arra, hogy garancikat
adjon olyan felhasznli objektumokra, melyek nem megfelelen mkdnek. A kivtelke-
zels szempontjbl a Safe s az Unsafe abban klnbzik, hogy a Safe a konstruktort hasz-
nlja az invarins (24.3.7.1) ltrehozshoz, ami lehetv teszi, hogy mveleteit egyszer-
en s biztonsgosan valstsuk meg. Ha az llapotbiztost felttel nem elgthet ki,
kivtelt kapunk, mieltt mg az rvnytelen objektum ltrejnne. Ugyanakkor az Unsafe
nem rendelkezik rtelmes invarinssal s a klnll mveletek mindenfle kivteleket vl-
tanak ki, anlkl, hogy egy kzponti hibakezel eljrs rendelkezskre llna. Termsze-
tesen ez gyakran vezet a standard knyvtr (sszer) felttelezseinek megsrtshez. Az
Unsafe esetben pldul rvnytelen elemek maradhatnak egy trolban, miutn
a T::operator=() egy kivtelt vltott ki, s a destruktor is eredmnyezhet kivteleket.
A standard knyvtr biztostsainak viszonya a rossz viselkeds felhasznli mveletek-
hez ugyanolyan, mint a nyelv biztostsainak viszonya a tpusrendszer szablyait megsrt
mveletekhez. Ha egy alapmveletet nem meghatrozott szablyai szerint hasznlunk, az
eredmny nem meghatrozhat lesz. Ha egy vector elemeinek destruktora kivtelt vlt ki,
ugyangy nincs jogunk logikus viselkedst elvrni, mint amikor egy kezdrtkknt
vletlenszmmal feltlttt mutatval szeretnnk adatokat elrni:
class Bomb {
public:
// ...
~Bomb() { throw Trouble(); }
};
vector<Bomb> b(10); // nem meghatrozhat viselkedshez vezet
void f()
{
int* p = reinterpret_cast<int*>(rand()); // nem meghatrozhat viselkedshez vezet
*p = 7;
}
Fggelkek s trgymutat 1264
De nzzk a dolgok j oldalt: ha betartjuk a nyelv s a standard knyvtr alapvet szab-
lyait, a knyvtr jl fog viselkedni gy is, ha kivteleket vltunk ki.
Amellett, hogy rendelkezsnkre ll a tiszta kivtelbiztossg, szeretjk elkerlni az erfor-
rsokban elfordul lyukakat; azaz egy olyan mveletnek, amely kivtelt vlt ki, nem elg
az operandusait meghatrozott llapotban hagynia, biztostania kell azt is, hogy minden
ignyelt erforrs valamikor felszabaduljon. Egy kivtel kivltsnak helyn pldul min-
den korbban lefoglalt memriaterletet fel kell szabadtanunk vagy azokat valamilyen ob-
jektumhoz kell ktnnk, hogy ksbb a memria szablyosan felszabadthat legyen.
A standard knyvtr biztostja, hogy nem lesznek erforrs-lyukak, ha azok a felhasznli
mveletek, melyeket a knyvtr hasznl, maguk sem hoznak ltre ilyeneket:
void leak(bool abort)
{
vector<int> v(10); // nincs memria-elszivrgs
vector<int>* p = new vector<int>(10); // memria-elszivrgs lehetsges
auto_ptr< vector<int> > q(new vector<int>(10)); // nincs memria-elszivrgs (14.4.2)
if (abort) throw Up();
// ...
delete p;
}
Ha kivtel kvetkezik be, a v vector s a q ltal mutatott vector helyesen lesz trlve, gy
minden ltaluk lefoglalt erforrs felszabadul. Ezzel szemben a p ltal mutatott vector ob-
jektumot nem vdjk a kivtelektl, gy az nem fog trldni. Ha a kdrszletet biztonsgos-
s akarjuk tenni, vagy magunknak kell felszabadtani a p ltal mutatott terletet a kivtel ki-
vltsa eltt, vagy biztostanunk kell, hogy valamilyen objektum pldul egy auto_ptr
(14.4.2) birtokolja azt s szablyosan felszabadtsa akkor is, ha kivtel kvetkezett be.
Figyeljk meg, hogy a nyelv szablyai a rszleges ltrehozssal, illetve megsemmistssel
kapcsolatban biztostjk, hogy a rszobjektumok s az adattagok ltrehozsakor bekvetke-
z kivteleket a standard knyvtr eljrsai minden kln erfeszts nlkl helyesen kezel-
jk (14.4.1). Ez minden kivtelekkel kapcsolatos eljrs esetben nagyon fontos alapelv.
Gondoljunk arra is, hogy nem a memria az egyetlen olyan erforrs, amelyben lyukak for-
dulhatnak el. A megnyitott fjlok, zrolsok, hlzati kapcsolatok s a szlak is olyan
rendszererforrsok, melyeket egy fggvnynek fel kell szabadtania vagy t kell adnia va-
lamely objektumnak egy kivtel kivltsa eltt.
E. Kivtelbiztossg a standard knyvtrban 1265
E.3. A kivtelbiztossgot megvalst eljrsok
A standard knyvtr szoks szerint bemutatja azokat a problmkat, amelyek sok ms
helyzetben is elfordulhatnak s ezekre olyan megoldst ad, ami szles krben felhasznl-
hat. A kivtelbiztos programok rsnak alapvet eszkzei a kvetkezk:
1. A try blokk (8.3.1)
2. A kezdeti rtkads az erforrs megszerzsvel eljrs (14.4)
A kvetend ltalnos elvek:
3. Soha ne dobjunk ki adatokat gy, hogy nem tudjuk pontosan, mi kerl
a helykre.
4. Az objektumokat mindig rvnyes llapotban hagyjuk, amikor kivtelt vltunk ki.
Ha betartjuk ezeket a szablyokat, minden hibt megfelelen kezelhetnk. Ezen elvek k-
vetse a gyakorlatban azrt jelent problmt, mert mg a legrtalmatlanabbnak tn eljr-
sok (pldul a <, az = vagy a sort()) is kivlthatnak kivteleket. Annak megllaptshoz,
hogy egy programban mit kell megvizsglnunk, nagy tapasztalatra van szksg.
Ha knyvtrat runk, clszer az ers kivtelbiztossgot (E.2) clul kitznnk s minden-
hol meg kell valstanunk az alapbiztostst. Programok rsakor a kivtelbiztossg kevs-
b fontos szempont. Pldul, amikor egy egyszer adatfeldolgoz programot ksztnk sa-
jt magunknak, ltalban nem baj, ha a program egyszeren befejezdik, amikor a virtulis
memria valamilyen hiba miatt elfogy. Ugyanakkor a helyessg s az alapvet kivtelbiz-
tossg szorosan kapcsoldik egymshoz.
Az alapvet kivtelbiztossg megvalstsra szolgl eljrsok pldul az llapotbiztos-
tk megadsa s fenntartsa (24.3.7.1) nagyon hasonltanak azokhoz, melyek segtsg-
vel kicsi s helyesen mkd programokat hozhatunk ltre. Ebbl kvetkezik, hogy az
alapvet kivtelbiztossg (az alapbiztosts; E.2) vagy akr az ers biztosts megval-
stsa csupn jelentktelen teljestmnyromlssal jr. Lsd: E.8[17]
Az albbiakban a vector szabvnyos trol (16.3) egy megvalstst adjuk meg, hogy be-
mutassuk, milyen feladatokat kell megoldanunk az idelis kivtelbiztossg megvalsts-
hoz s hol rdemes alaposabb felgyeletet biztostanunk.
Fggelkek s trgymutat 1266
E.3.1. Egy egyszer vektor
A vector (16.3) leggyakoribb megvalstsban hrom mutat (vagy az ezzel egyenrtk
mutateltols pr) szerepel: egy az els elemre, egy az utols utni elemre s egy az utol-
s utni lefoglalt helyre hivatkozik (17.1.3):
Lssuk, mire van szksgnk a vector deklarcijban, ha csak a kivtelbiztossg s az er-
forrs-lyukak elkerlse szempontjbl vizsgljuk az osztlyt:
template<class T, class A = allocator<T> >
class vector {
private:
T* v; // a lefoglalt terlet eleje
T* space; // az elemsorozat vge, bvts szmra tartalkolt terlet kezdete
T* last; // a lefoglalt terlet vge
A alloc; // memriafoglal
public:
explicit vector(size_type n, const T& val = T(), const A& = A());
vector(const vector& a); // msol konstruktor
vector& operator=(const vector& a); // msol rtkads
~vector();
size_type size() const { return space-v; }
size_type capacity() const { return last-v; }
void push_back(const T&);
// ...
};
E. Kivtelbiztossg a standard knyvtrban 1267
vector:
first
space
last
tartalk hely elemek
Vizsgljunk elszr egy meggondolatlan konstruktor-megvalstst:
template<class T, class A>
vector<T,A>::vector(size_type n, const T& val, const A& a) // vigyzat: nav megvalsts
: alloc(a) // memriafoglal msolsa
{
v = alloc.allocate(n); // memria lefoglalsa az elemek szmra (19.4.1)
space = last = v+n;
for (T* p = v; p!=last; ++p) a.construct(p,val); // val ltrehoz msolsa *p-be (19.4.1)
}
Itt hrom helyen keletkezhet kivtel:
1. Az allocate() fggvny kivtelt vlthat ki, ha nincs elegend memria.
2. A memriafoglal (alloktor) msol konstruktora is eredmnyezhet kivtelt.
3. A T elemtpus msol konstruktora is kivlthat kivtelt, ha nem tudja lemsolni
a val rtket.
Egyik esetben sem jn ltre j objektum, teht a vector konstruktora sem fut le (14.4.1).
Ha az allocate() vgrehajtsa sikertelen, a throw mr akkor kilp a konstruktorbl, amikor
mg semmilyen erforrst nem foglaltunk le, gy ezzel minden rendben.
Ha a T msol konstruktora eredmnyez hibt, mr lefoglaltunk valamennyi memrit, gy
azt fel kell szabadtanunk, ha el akarjuk kerlni a memria-elszivrgst. Az igazn nagy
problmt az jelenti, hogy a T msol konstruktora esetleg akkor vlt ki kivtelt, amikor
mr nhny objektumot sikeresen ltrehozott, de mg nem az sszeset.
Ezen problma kezelshez nyilvn kell tartanunk, hogy eddig mely elemeket hoztuk lt-
re, s amikor hiba kvetkezik be, ezeket (s csak ezeket) trlnnk kell:
template<class T, class A>
vector<T,A>::vector(size_type n, const T& val, const A& a) // jl kidolgozott megvalsts
: alloc(a) // memriafoglal msolsa
{
v = alloc.allocate(n); // memria lefoglalsa az elemek szmra
iterator p;
try {
iterator end = v+n;
for (p=v; p!=end; ++p) alloc.construct(p,val); // elemek ltrehozsa (19.4.1)
last = space = p;
}
Fggelkek s trgymutat 1268
catch (...) {
for (iterator q = v; q!=p; ++q) alloc.destroy(q); // ltrehozott elemek megsemmistse
alloc.deallocate(v,n); // memria felszabadtsa
throw; // tovbbdobs
}
}
A pluszkltsg ez esetben is csak a try blokk kltsge. Egy j C++-vltozatban ez elhanya-
golhat a memriafoglalshoz s az elemek kezdeti rtkadshoz kpest. Ahol a try blokk
kltsge magas, esetleg beilleszthetjk az if(n) vizsglatot a try el, ezzel az res vektort k-
ln esetknt kezelhetjk.
A konstruktor nagy rszt az uninitialized_fill() fggvny kivtelbiztos megvalstsa tlti ki:
template<class For, class T>
void uninitialized_fill(For beg, For end, const T& x)
{
For p;
try {
for (p=beg; p!=end; ++p)
new(static_cast<void*>(&*p)) T(x); // x ltrehoz msolsa *p-ben (10.4.11)
}
catch (...) { // a ltrehozott elemek trlse s tovbbdobs:
for (For q = beg; q!=p; ++q) (&*q)->~T(); // (10.4.11)
throw;
}
}
A furcsa &*p kifejezsre azrt volt szksg, hogy a nem mutat bejrkat (itertorokat) is
kezelhessk. Ilyenkor ahhoz, hogy mutatt kapjunk, a hivatkozssal meghatrozott elem
cmt kell vennnk. A void* talakts biztostja, hogy a standard knyvtr elhelyez fgg-
vnyt hasznljuk (19.4.5), nem a felhasznl ltal a T* tpusra megadott operator new()
fggvnyt. Ez az eljrs olyan alacsony szinten mkdik, ahol a teljes ltalnossgot mr
elg nehz biztostani.
Szerencsre nem kell jrarnunk az uninitialized_fill() fggvnyt, mert a standard knyv-
tr biztostja hozz a megkvnt ers biztostst (E.2). Gyakran elengedhetetlen , hogy
olyan kezdrtk-ad mvelet lljon rendelkezsnkre, amely vagy minden elemet hibt-
lanul tlt fel kezdrtkkel, vagy hiba esetn egyltaln nem ad vissza elemeket. ppen
ezrt a standard knyvtrban szerepl uninitialized_fill(), uninitialized_fill_n() s
uninitialized_copy() fggvny (19.4.4) biztostja ezt az ers kivtelbiztossgot (E.4.4).
E. Kivtelbiztossg a standard knyvtrban 1269
Figyeljk meg, hogy az uninitialized_fill() nem vdekezik az elemek destruktora vagy
a bejrmveletek ltal kivltott kivtelek ellen (E.4.4), ez ugyanis elviselhetetlenl nagy
kltsget jelentene (lsd E.8[16-17]).
Az uninitialized_fill() nagyon sokfle sorozatra alkalmazhat, ezrt csak elre halad be-
jrkat vesz t (19.2.1), amivel viszont nem tudja garantlni, hogy az elemeket ltrehoz-
sukkal fordtott sorrendben trli.
Az uninitialized_fill() felhasznlsval az albbiakat rhatjuk:
template<class T, class A>
vector<T,A>::vector(size_type n, const T& val, const A& a) // zavaros megvalsts
:alloc(a) // memriafoglal msolsa
{
v = alloc.allocate(n); // memria lefoglalsa az elemek szmra
try {
uninitialized_fill(v,v+n,val); // elemek msolsa
space = last = v+n;
}
catch (...) {
alloc.deallocate(v,n); // memria felszabadtsa
throw; // tovbbdobs
}
}
Ennek ellenre ezt a programot nem nevezhetjk szpnek. A kvetkezkben bemutatjuk,
hogyan tehetjk a programot sokkal egyszerbb.
Figyeljk meg, hogy a konstruktor jra kivltja azt a kivtelt, amit elkapott. A cl az, hogy
a vector osztlyt tltszv tegyk a kivtelek eltt, mert gy a felhasznl pontosan meg-
llapthatja a hiba okt. A standard knyvtr sszes trolja rendelkezik ezzel a tulajdon-
sggal. A kivtelekkel szembeni tltszsg gyakran a legjobb lehetsg a sablonok s a ha-
sonl vkony rtegek szmra. Ez ellenttben ll a programrendszerek nagyobb
rszeinek (moduljainak) irnyvonalval, hiszen ezeknek ltalban nllan kell kezelni-
k minden hibt. Pontosabban, az ilyen modulok ksztinek fel kell tudniuk sorolni az
sszes kivtelt, amit a modul kivlthat. Ennek megvalstshoz vagy a kivtelek csoporto-
stsra (14.2), vagy az alacsonyszint eljrsok s a modul sajt kivteleinek sszekapcso-
lsra (14.6.3), esetleg a kivtelek meghatrozsra (14.6) van szksg.
Fggelkek s trgymutat 1270
E.3.2. A memria brzolsa
A tapasztalatok bebizonytottk, hogy helyes, kivtelbiztos programok ksztse try blokkok
segtsgvel bonyolultabb annl, mint amit egy tlagos programoz mg elfogad. Valjban
feleslegesen bonyolult, hiszen van egy msik lehetsg: a kezdeti rtkads az erforrs
megszerzsvel (14.4), melynek segtsgvel cskkenthetjk azon programsorok szmt,
melyek egy stlusos program megvalstshoz szksgesek. Esetnkben a legfontosabb
erforrs, amire a vector osztlynak szksge van, egyrtelmen a memria, melyben az
elemeket troljuk. Ha bevezetnk egy segdosztlyt, amely a vector ltal hasznlt memri-
t brzolja, leegyszersthetjk programunkat s cskkenthetjk annak eslyt, hogy v-
letlenl elfelejtjk felszabadtani a memrit.
template<class T, class A = allocator<T> >
struct vector_base {
A alloc; // memriafoglal
T* v; // a lefoglalt terlet eleje
T* space; // az elemsorozat vge, bvts szmra tartalkolt terlet kezdete
T* last; // a lefoglalt terlet vge
vector_base(const A& a, typename A::size_type n)
: alloc(a), v(a.allocate(n)), space(v+n), last(v+n) { }
~vector_base() { alloc.deallocate(v,last-v); }
};
Amg a v s a last mutat helyes, a vector_base objektum megsemmisthet. A vector_base
osztly a T tpus szmra lefoglalt memrit kezeli s nem T tpus objektumokat, ezrt mi-
eltt egy vector_base objektumot trlnk, minden ennek segtsgvel ltrehozott objektu-
mot is trlnnk kell.
Termszetesen magt a vector_base osztlyt is gy kell megrni, hogy ha kivtel kvetkezik
be (a memriafoglal msol konstruktorban vagy az allocate() fggvnyben), ne jjjn
ltre vector_base objektum, gy memria-elszivrgs sem kvetkezik be.
A vector_base felhasznlsval a vector osztlyt a kvetkezkppen hatrozhatjuk meg:
template<class T, class A = allocator<T> >
class vector : private vector_base<T,A> {
void destroy_elements() { for (T* p = v; p!=space; ++p) p->~T(); } // 10.4.11
public:
explicit vector(size_type n, const T& val = T(), const A& = A());
E. Kivtelbiztossg a standard knyvtrban 1271
vector(const vector& a); // msol konstruktor
vector& operator=(const vector& a); // msol rtkads
~vector() { destroy_elements(); }
size_type size() const { return space-v; }
size_type capacity() const { return last-v; }
void push_back(const T&);
// ...
};
A vector destruktora az sszes elemre egyms utn meghvja a T tpus destruktort. Ebbl
kvetkezik, hogy ha egy elem destruktora kivtelt vlt ki, a vector destruktora sem tud hi-
btlanul lefutni. Ez igen nagy problmt okoz, ha egy msik kivtel miatt kezdemnyezett
verem-visszatekers kzben kvetkezik be, hiszen ekkor a terminate() fggvny fut le
(14.7). Ha a destruktor kivtelt vlt ki, ltalban erforrs-lyukak keletkeznek s azok az
eljrsok, melyeket szablyos viselkeds objektumokhoz fejlesztettek ki, megjsolhatatla-
nul fognak mkdni. Nem igazn van hasznlhat megolds a destruktorokban keletkez
kivtelek kezelsre, ezrt a knyvtr semmilyen biztostst nem vllal, ha az elemek ilyen
viselkedsek lehetnek (E.4).
A konstruktort az albbi egyszer formban adhatjuk meg:
template<class T, class A>
vector<T,A>::vector(size_type n, const T& val, const A& a)
: vector_base<T,A>(a,n) // terlet lefoglalsa n elem szmra
{
uninitialized_fill(v,v+n,val); // elemek msolsa
}
A msol konstruktor mindssze abban klnbzik ettl, hogy az uninitialized_fill() he-
lyett az uninitialized_copy() fggvnyt hasznlja:
template<class T, class A>
vector<T,A>::vector(const vector<T,A>& a)
: vector_base<T,A>(a.alloc,a.size())
{
uninitialized_copy(a.begin(),a.end(),v);
}
Fggelkek s trgymutat 1272
Figyeljk meg, hogy az ilyen stlus konstruktor kihasznlja a nyelvnek azon alapszablyt,
hogy ha a konstruktorban kivtel keletkezik, azokra a rszobjektumokra (s alapobjektu-
mokra), melyek sikeresen ltrejttek, a destruktor is szablyosan lefut (14.4.1). Az
uninitialized_fill() s testvrei (E.4.4) ugyanilyen szolgltatst nyjtanak a flig ltrehozott
sorozatok esetben.
E.3.3. rtkads
Szoks szerint az rtkads abban klnbzik a ltrehozstl, hogy a korbbi rtkekre is
figyelnnk kell. Vizsgljuk meg az albbi megvalstst:
template<class T, class A>
vector<T,A>& vector<T,A>::operator=(const vector& a) // ers biztostst ad (E.2)
{
vector_base<T,A> b(alloc,a.size()); // memria lefoglalsa
uninitialized_copy(a.begin(),a.end(),b.v); // elemek msolsa
destroy_elements();
alloc.deallocate(v,last-v); // a rgi memriaterlet felszabadtsa
vector_base::operator=(b); // brzols elhelyezse
b.v = 0; // felszabadts megelzse
return *this;
}
Ez az rtkads szp s kivtelbiztos is, de tl sok mindent ismtel meg a konstruktorbl s
a destruktorbl. Ennek elkerlsre a kvetkez eljrst rhatjuk:
template<class T, class A>
vector<T,A>& vector<T,A>::operator=(const vector& a) // ers biztostst ad (E.2)
{
vector temp(a); // "a" msolsa
swap< vector_base<T,A> >(*this,temp); // brzolsok felcserlse
return *this;
}
A rgi elemeket a temp destruktora trli, az ltaluk lefoglalt terletet pedig a temp vltoz
vector_base objektumnak destruktora szabadtja fel.
A kt vltozat teljestmnye szinte teljesen egyenl. Valjban csak kt klnbz formban
adjuk meg ugyanazokat a mveleteket. A msodik megvalsts viszont rvidebb s nem is-
mtli a vector osztly egyb fggvnyeiben mr szerepl kdrszleteket, gy az rtkads
ezen vltozata kevesebb hibalehetsget tartalmaz s egyszerbb rendben tartani is.
E. Kivtelbiztossg a standard knyvtrban 1273
Figyeljk meg, hogy az nrtkads szoksos vizsglata hinyzik az eljrsbl (10.4.4):
if (this == &a) return *this;
Ezek az rtkad mveletek elszr ltrehoznak egy msolatot, majd lecserlik az eleme-
ket. Ez a megolds automatikusan kezeli az nrtkads problmjt. gy dntttem, hogy
a ritkn elfordul nrtkads kln vizsglata nem jr annyi haszonnal, hogy rdemes le-
gyen ezzel lasstani az ltalnos esetet, amikor egy msik vector objektumot adunk rtkl.
Mindkt esetben kt, esetleg jelents optimalizlsi lehetsg hinyzik:
1. Ha az rtket kap vektor mrete elg nagy ahhoz, hogy az rtkl adott vek-
tort trolja, nincs szksg j memria lefoglalsra.
2. Az elemek kztti rtkads hatkonyabb lehet, mint egy elem trlse, majd
kln ltrehozsa.
Ha ezeket a javtsokat is beptjk, a kvetkez eredmnyt kapjuk:
template<class T, class A>
vector<T,A>& vector<T,A>::operator=(const vector& a) // optimalizlt, alapbiztosts (E.2)
{
if (capacity() < a.size()) { // j vektorbrzols szmra terlet lefoglalsa
vector temp(a); // "a" msolsa
swap< vector_base<T,A> >(*this,temp); // az brzolsok felcserlse
return *this;
}
if (this == &a) return *this; // vdelem az nrtkads ellen (10.4.4)
// a rgi elemek rtkadsa
size_type sz = size();
size_type asz = a.size();
alloc = a.get_allocator(); // memriafoglal msolsa
if (asz<=sz) {
copy(a.begin(),a.begin()+asz,v);
for (T* p = v+asz; p!=space; ++p) p->~T(); // felesleges elemek felszmolsa (10.4.11)
}
else {
copy(a.begin(),a.begin()+sz,v);
uninitialized_copy(a.begin()+sz,a.end(),space); // tovbbi elemek ltrehozsa
}
space = v+asz;
return *this;
}
Fggelkek s trgymutat 1274
Ezek az optimalizcik nem valsthatk meg bntetlenl. A copy() eljrs nem nyjt ers
kivtelbiztostst, mert nem garantlja, hogy a cl vltozatlan marad, ha msols kzben ki-
vtel kvetkezik be. Teht ha a T::operator=() kivtelt vlt ki a copy() mvelet kzben, el-
fordulhat, hogy az rtket kap vektor megvltozik, de nem lesz az rtkl adott vektor
pontos msolata. Lehetsges pldul, hogy az els t elemet sikerl lemsolni az rtkl
adott vektorbl, de a tbbi vltozatlan marad, st akr az is elkpzelhet, hogy egy elem
(az, amelyiket ppen msoltuk, amikor a T::operator=() kivtelt vltott ki) olyan rtket fog
tartalmazni, amely nem egyezik meg sem az eredetivel, sem a msolandval. Azt azrt el-
mondhatjuk, hogy ha a T::operator=() rvnyes llapotban hagyja operandust egy kivtel
kivltsakor is, a teljes vector is rvnyes llapotban marad, br nem abban az llapotban,
amit szerettnk volna.
A fentiekben a memriafoglalt is rtkadssal msoltuk le. Valjban a memriafoglalk-
tl nem mindig kveteljk meg, hogy rendelkezzenek rtkadssal (19.4.3, lsd
mg:E.8[9]).
A standard knyvtr vector rtkadsnak legutbbi megvalstsa gyengbb kivtelbiztos-
sgot, de nagyobb hatkonysgot biztost. Csak az alapbiztostst nyjtja, ami megfelel
a legtbb programoz kivtelbiztossgrl alkotott fogalmnak, de nem ll rendelkezsnk-
re ers biztosts (E.2). Ha olyan rtkadsra van szksgnk, amely kivtel fellptekor
a vector-t vltozatlanul hagyja, olyan knyvtr-megvalstst kell hasznlnunk, amely ers
biztostst nyjt az ilyen helyzetekben is vagy sajt magunknak kell megrni az rtkad
mveletet:
template<class T, class A>
void safe_assign(vector<T,A>& a, const vector<T,A>& b) // "magtl rtend" a = b
{
vector<T,A> temp(a.get_allocator());
temp.reserve(b.size());
for (typename vector<T,A>::iterator p = b.begin(); p!=b.end(); ++p)
temp.push_back(*p);
swap(a,temp);
}
Ha nincs elegend memria ahhoz, hogy ltrehozzuk a temp vltozt b.size() elem szm-
ra, az std:bad_alloc kivtelt vltjuk ki, mieltt brmilyen vltoztatst vgeznnk az a vekto-
ron. Ehhez hasonlan, ha a push_back() vgrehajtsa nem sikerl, az a akkor is rintetlen
marad, hiszen minden push_back() mveletet a temp objektumon hajtunk vgre az a he-
lyett. Ezzel a megoldssal azt is biztostjuk, hogy felszabaduljon a temp minden eleme, amit
a push_back() segtsgvel ltrehoztunk, mieltt a hibt okoz kivtelt jra kivltannk.
E. Kivtelbiztossg a standard knyvtrban 1275
A swap() nem msolja a vektorok elemeit, csupn lecserli a vector adattagjait, gy
a vector_base objektumot is. Ennek kvetkeztben a swap() akkor sem vlthat ki kivtelt,
ha az elemek mveletei kpesek erre (E.4.3). A safe_assign() nem kszt felesleges mso-
latokat az elemekrl, teht elg hatkony tud lenni.
Szoks szerint vannak ms lehetsgek is a nyilvnval megvalsts mellett, pldul rbz-
hatjuk magra a knyvtrra, hogy az elemeket az ideiglenes vektorba msolja:
template<class T, class A>
void safe_assign(vector<T,A>& a, const vector<T,A>& b) // egyszer a = b
{
vector<T,A> temp(b); // b elemeinek msolsa az ideiglenes vltozba
swap(a,temp);
}
St, egyszer rtk szerinti paramtertadst (7.2) is hasznlhatunk:
template<class T, class A>
void safe_assign(vector<T,A>& a, vector<T,A> b) // egyszer a = b
// (figyelem: b rtk szerint tadva)
{
swap(a,b);
}
A safe_assign() ez utbbi kt vltozata a vector memriafoglaljt nem msolja le, ami meg-
engedett optimalizci (lsd 19.4.3).
E.3.4. A push_back()
A kivtelbiztossg szemszgbl nzve a push_back() nagyon hasonlt az rtkadsra ab-
ban, hogy nem szabad a vector objektumot megvltoztatnunk, ha az j elem beillesztse va-
lamilyen problmba tkzik:
template< class T, class A>
void vector<T,A>::push_back(const T& x)
{
if (space == last) { // nincs tbb hely; thelyezs
vector_base b(alloc,size()?2*size():2); // a lefoglals megkettozse
uninitialized_copy(v,space,b.v);
new(b.space) T(x); // x msolatnak *b.space-be helyezse (10.4.11)
++b.space;
destroy_elements();
Fggelkek s trgymutat 1276
swap<vector_base<T,A> >(b,*this); // az brzolsok felcserlse
return;
}
new(space) T(x); // x msolatnak *space-be helyezse (10.4.11)
++space;
}
Termszetesen, a *space kezdeti rtkadsra szolgl msol konstruktor vlthat ki kiv-
telt. Ha ez trtnik, a vector vltozatlan marad s a space rtkt sem nveljk meg. Ilyen-
kor a vektor elemeit sem kell thelyeznnk a memriban, teht az eddigi bejrk is r-
vnyben maradnak. gy ez a megvalsts ers biztostst ad: ha egy memriafoglal vagy
egy felhasznli eljrs kivtelt vlt ki, a vector nem vltozik meg. A standard knyvtr ilyen
biztostst nyjt a push_back() fggvnyhez (E.4.1).
Figyeljk meg, hogy az eljrsban nincs egyetlen try blokk sem (attl eltekintve, ami az
uninitialized_copy() fggvnyben, rejtve szerepel). A mdostst a mveletek sorrendj-
nek pontos megvlasztsval hajtjuk vgre, gy ha kivtel keletkezik, a vektor rtke nem
vltozik meg.
Ez a megkzelts miszerint az utastsok sorrendje adja a kivtelbiztossgot s a kez-
deti rtkads az erforrs megszerzsvel (14.4) alkalmazsa elegnsabb s hatko-
nyabb megoldst knl, mint a hibk kifejezett kezelse try blokkok segtsgvel. Ha utas-
tsainkat szerencstlen sorrendben rjuk le, sokkal tbb kivtelbiztossgi problmval kell
megkzdennk, mint a kivtelkezel eljrsok elhagysa mellett. A sorrend meghatroz-
sakor az alapszably az, hogy ne semmistsnk meg informcit, mieltt az azt helyettest
adatokat ltre nem hoztuk s nem biztostottuk, hogy azokat kivtelek veszlye nlkl tr-
hassuk a helykre.
A kivtelkezels egyik kvetkezmnye, hogy a program vgrehajtsa sorn a vezrls meg-
lep helyekre kerlhet. Az olyan egyszer, helyi vezrlssel rendelkez fggvnyekben,
mint az operator=(), a safe_assign() vagy a push_back(), meglepetsek ritkbban fordulnak
el. Ha rnznk egy kdrszletre, viszonylag egyszeren megllapthatjuk, hogy egy adott
sor vlthat-e ki kivtelt s mi lesz annak kvetkezmnye. A nagyobb fggvnyekben, me-
lyekben bonyolult vezrlsi szerkezeteket (pldul bonyolult feltteles utastsokat s egy-
msba gyazott ciklusokat) hasznlunk, az ilyen krdsekre nehz vlaszt adni. A try blok-
kok alkalmazsa a helyi vezrlst mg tovbb bonyoltja, gy jabb keveredseket s
hibkat eredmnyezhet (14.4). Azt hiszem, az utastsrendezs s a kezdeti rtkads az
erforrs megszerzsvel hatkonysga a nagyobb mret try blokkokkal szemben ppen
a helyi vezrls egyszerstsben rejlik. Egyszerbben fogalmazva, a stlusos programo-
kat egyszerbb megrteni s egyszerbb helyesen megrni.
E. Kivtelbiztossg a standard knyvtrban 1277
Gondoljunk r, hogy az itt szerepl vector csak a kivtelek ltal okozott problmk s az
ezen problmk megoldsra kidolgozott eljrsok bemutatsra szolgl. A szabvny nem
kveteli meg, hogy minden megvalsts pontosan gy nzzen ki, ahogy itt bemutatjuk.
A szabvny ltal biztostott garancikat az E.4. pontban trgyaljuk.
E.3.5. Konstruktorok s invarinsok
A kivtelbiztossg szemszgbl nzve a vector tbbi mvelete vagy ugyangy viselkedik,
mint az eddig bemutatottak (mivel hasonl mdon foglalnak le s szabadtanak fel erfor-
rsokat), vagy megvalstsuk egyszer (mert nem vgeznek olyan tevkenysget, amely-
ben az rvnyes llapot fenntartsa problmt okozhatna). A legtbb osztlyban ezek a tri-
vilis fggvnyek jelentik a dnt tbbsget. Az ilyen eljrsok bonyolultsga elssorban
attl fgg, hogy a konstruktor milyen mkdsi krnyezetet biztost szmukra. Mskppen
fogalmazva, az ltalnos tagfggvnyek bonyolultsga elssorban a j osztlyinvarins
megvlasztsn mlik (24.3.7.1). Az egyszer vektormveletek vizsglatval megrthetjk,
mitl lesz j egy osztlyinvarins s hogyan kell megrnunk a konstruktorokat ahhoz, hogy
ezeket az invarinsokat biztostsk.
Az olyan mveleteket, mint a vektorok indexelse (16.3.3) azrt knny megvalstani,
mert ersen ptenek arra az invarinsra, amit a konstruktor hoz ltre s az erforrsokat
lefoglal, illetve felszabadt fggvnyek tartanak fenn. Az indexel mvelet pldul hivat-
kozhat a v tmbre, amely az elemeket trolja:
template< class T, class A>
T& vector<T,A>::operator[](size_type i)
{
return v[i];
}
Nagyon fontos s alapvet szably, hogy a konstruktornak kell lefoglalnia az erforrsokat
s biztostania kell egy egyszer invarinst. Ahhoz, hogy ennek fontossgt megrtsk, nz-
zk meg a vector_base defincijnak albbi vltozatt:
template<class T, class A = allocator<T> > // a konstruktor esetlen hasznlata
class vector_base {
public:
A alloc; // memriafoglal
T* v; // a lefoglalt terlet eleje
T* space; // az elemsorozat vge, bvts szmra tartalkolt terlet kezdete
T* last; // a lefoglalt terlet vge
Fggelkek s trgymutat 1278
vector_base(const A& a, typename A::size_type n) : alloc(a), v(0), space(0), last(0)
{
v = alloc.allocate(n);
space = last = v+n;
}
~vector_base() { if (v) alloc.deallocate(v,last-v); }
};
Itt a vector_base objektumot kt lpsben hozzuk ltre. Elszr egy biztonsgi llapotot
alaktunk ki, amely a v, a space s a last vltozt 0-ra lltja, s csak ezutn prblunk me-
mrit foglalni. Ez arra az indokolatlan flelemre vezethet vissza, hogy az elemek lefogla-
lsa kzben keletkez kivtelek miatt flig ltrejtt objektumot hozhatunk ltre. A flelem
azrt indokolatlan, mert ilyen objektumot egyltaln nem hozhatunk ltre. A szablyok,
melyek a statikus, automatikus, illetve tagobjektumok s a standard knyvtr trolinak
elemeire vonatkoznak, megakadlyozzk ezt. Azokban a szabvny eltti knyvtrakban
azonban, melyek a trolkban elhelyez new opertort (10.4.11) hasznltak (hasznlnak)
az objektumok ltrehozsra s nem foglalkoztak (foglalkoznak) a kivtelbiztossggal, ez
elfordulhatott (elfordulhat). A megrgztt szoksokon nehz vltoztatni.
Figyeljk meg, hogy a biztonsgosabb program ellltsra irnyul prblkozs tovbb
bonyoltja az osztlyinvarinst: nem lehetnk biztosak abban, hogy a v egy ltez, lefoglalt
memriaterletre mutat, mert szerepelhet benne a 0 rtk is. Ez a hiba azonnal megbosszul-
ja magt. A standard knyvtr nem kveteli meg a memriafoglalktl, hogy egy 0 rtket
tartalmaz mutatt biztonsgosan szabadtsanak fel (19.4.1). A memriafoglalk ebben el-
trnek a delete mvelettl (6.2.6). Ebbl kvetkezik, hogy a destruktorban kln ellenr-
zst kell vgeznnk. Ezenkvl minden elemnek kezdrtket adunk s csak ksbb rtel-
mes rtket. Ezen kltsgek egy olyan elemtpus esetben lehetnek jelentsek, ahol az
rtkads bonyolult, pldul a string vagy a list osztlynl.
A ktlpses ltrehozs nem szokatlan megolds. Gyakran olyan formban jelenik meg,
hogy a konstruktor csak egy egyszer s biztonsgos kezdeti rtkadst vgez, mellyel az
objektum trlhet llapotba kerl. A valdi kezdeti rtkadst egy init() fggvny vgzi
el, melyet a felhasznlnak kln meg kell hvnia:
template<class T> // rgies (szabvny s kivtelkezels eltti) stlus
class vector_base {
public:
T* v; // a lefoglalt terlet eleje
T* space; // az elemsorozat vge, bvts szmra tartalkolt terlet kezdete
T* last; // a lefoglalt terlet vge
E. Kivtelbiztossg a standard knyvtrban 1279
vector_base() : v(0), space(0), last(0) { }
~vector_base() { free(v); }
bool init(size_t n) // igazat ad vissza, ha a kezdeti rtkads sikerlt
{
if (v = (T*)malloc(sizeof(T)*n)) {
uninitialized_fill(v,v+n,T());
space = last = v+n;
return true;
}
return false;
}
};
Ezen stlus lthat elnyei a kvetkezk:
1. A konstruktor nem vlthat ki kivtelt s az init() segtsgvel megvalstott kez-
deti rtkads sikeressgt a szoksos mdszerekkel (azaz nem kivtelekkel)
ellenrizhetjk.
2. rvnyes llapot ll rendelkezsnkre, melyet brmely mvelet komoly probl-
ma esetn is biztostani tud.
3. Az erforrsok lefoglalst mindaddig halaszthatjuk, amg tnylegesen szks-
gnk nincs kezdrtkkel rendelkez objektumokra.
A kvetkez rszfejezetekben ezeket a szempontokat vizsgljuk meg s bemutatjuk, hogy
a ktlpses ltrehozs mirt nem biztostja az elvrt elnyket, amellett, hogy ms probl-
mkat is felvet.
E.3.5.1. Az init() fggvny hasznlata
Az els pont (az init() eljrs hasznlata a konstruktor helyett) valjban nem is elny.
A konstruktorok s kivtelek hasznlata sokkal ltalnosabb s rendezettebb megolds az
erforrs-lefoglalsi hibk s a kezdeti rtkadssal kapcsolatos problmk kezelsre
(14.1, 14.4). Ez a stlus a kivtelek nlkli C++ maradvnya.
Ha a kt stlusban ugyanolyan figyelmesen runk meg egy programot, azt tapasztalhatjuk,
hogy kt, szinte teljesen egyenrtk eredmnyt kapunk. Az egyik:
int f1(int n)
{
vector<X> v;
// ...
Fggelkek s trgymutat 1280
if (v.init(n)) {
// "v" n elem vektora
}
else {
// a problma kezelse
}
}
Mg msik vltozat:
int f2(int n)
try {
vector v<X> v(n);
// ...
// "v" n elem vektora
}
catch (...) {
// a problma kezelse
}
A kln init() fggvny hasznlata viszont lehetsget ad az albbi hibk elkvetsre:
1. Elfelejtjk meghvni az init() fggvnyt (10.2.3).
2. Elfelejtjk megvizsglni, hogy az init() sikerrel jrt-e.
3. Elfelejtjk, hogy az init() kivteleket vlthat ki.
4. Hasznlni kezdnk egy objektumot, mieltt meghvnnk az init() eljrst.
A vector<T>::init() defincija a [3] pontra mutat pldt.
Egy j C++-vltozatban az f2() egy kicsit gyorsabb is, mint az f1(), mert az ltalnos eset-
ben nem vgez ellenrzst.
E.3.5.2. Alaprtelmezett rvnyes llapot
A msodik pont (miszerint egy knnyen elllthat, alaprtelmezett rvnyes llapot ll
rendelkezsnkre) ltalban tnyleg elny, de a vector esetben ez felesleges kltsgeket
jelent, ugyanis elkpzelhet olyan vector_base, ahol v==0 s a vector megvalstsnak
mindenhol vdekeznie kell ez ellen:
template< class T>
T& vector<T>::operator[](size_t i)
{
E. Kivtelbiztossg a standard knyvtrban 1281
if (v) return v[i];
// hibakezels
}
Ha megengedjk a v==0 llapotot, a tartomny-ellenrzs nlkli indexels ugyanolyan
lass lesz, mint az ellenrztt hozzfrs:
template< class T>
T& vector<T>::at(size_t i)
{
if (i<v.size()) return v[i];
throw out_of_range("vector index");
}
Itt alapjban vve annyi trtnt, hogy a vector_base eredeti invarinst tlbonyoltottuk, az-
zal, hogy bevezettk a v==0 lehetsget. Ennek kvetkeztben a vector eredeti invarinst
is ugyangy kellett mdostanunk, teht a vector s a vector_base minden eljrst bonyo-
lultabban kell megfogalmaznunk. Ez szmtalan hiba forrsa lehet, pldul nehezebb lesz
a kd mdostsa s a program lassabban fog futni. Gondoljunk arra, hogy a modern kip-
ts szmtgpeknl a feltteles utastsok meglepen kltsgesek lehetnek. Ha fontos
a hatkonysg, a kulcsmveletek pldul a vektorindexels feltteles utastsok nlk-
li megvalstsa elsrend kvetelmny lehet.
rdekes mdon, mr a vector_base eredeti meghatrozsa is biztost egy knnyen ltrehoz-
hat rvnyes llapotot. Csak akkor ltezhet egy vector_base objektum, ha a kezdeti hely-
foglals sikeres volt. Ebbl kvetkezik, hogy a vector rjnak biztostania kell egy vszki-
jrat fggvnyt, pldul a kvetkez formban:
template< class T, class A>
void vector<T,A>::emergency_exit()
{
space = v; // *this mretnek 0-ra lltsa
throw Total_failure();
}
Ez a megolds tlsgosan drasztikus, mert nem hvja meg az elemek destruktorait s nem
szabadtja fel a vector_base objektumban az elemek ltal elfoglalt terletet. Rviden fogal-
mazva, nem nyjt alapbiztostst (E.2). Ha figyelnk a v s a space adattag tartalmra s az
elemek destruktoraira, elkerlhetjk az erforrs-lyukak kialakulst:
template< class T, class A>
void vector<T,A>::emergency_exit()
{
Fggelkek s trgymutat 1282
destroy_elements(); // takarts
throw Total_failure();
}
Figyeljk meg, hogy a szabvnyos vector olyan egyszer szerkezet, amely a lehet legki-
sebbre cskkenti a ktlpses ltrehozs miatt jelentkez problmk lehetsgt. Az init()
fggvny szinte egyenrtk a resize() eljrssal, a v==0 lehetsget pedig a legtbb eset-
ben a size()==0 vizsglat elvgzsvel is kezelhetjk. A ktlpses ltrehozs eddig bemu-
tatott negatv hatsai mg ersebben jelentkeznek, ha programunkban szerepel egy olyan
osztly, amelynek jelents erforrsokra pldul hlzati kapcsolatra vagy kls llom-
nyokra van szksge. Ezek az osztlyok ritkn kpezik egy olyan keretrendszer rszt,
amely felgyeli hasznlatukat s megvalstsukat, olyan formban, ahogy a standard
knyvtr kvetelmnyei felgyelik a vector hasznlatt. A problmk szma mg tovbb
nvekszik, ha az alkalmazs cljai s a megvalstsukhoz szksges erforrsok kapcso-
lata bonyolult. Nagyon kevs olyan osztly van, amely annyira kzvetlenl kapcsoldik
a rendszer erforrsaihoz, mint a vector.
Az egyszer biztonsgos llapot ltezsnek elve alapjban vve nagyon hasznos. Ha egy
objektumot nem tudunk rvnyes llapotba lltani anlkl, hogy kivtelektl kellene tar-
tanunk a mvelet befejezse eltt, valban problmink lehetnek. A biztonsgos llapot-
nak viszont az osztly szerephez termszetesen kell kapcsoldnia, nem erltetett mdon,
az osztly invarinst bonyoltva.
E.3.5.3. Az erforrs-lefoglals ksleltetse
A msodik ponthoz hasonlan (E.3.5.2) a harmadik is egy j tlet rossz megvalstsa, ami
nyeresg helyett inkbb vesztesget eredmnyez. A legtbb esetben klnsen az olyan
trolkban, mint a vector az erforrs-lefoglals ksleltetsnek legjobb mdja a progra-
moz szmra az, hogy magt az objektumot hozza ltre, amikor szksge van r. Nzzk
meg pldul a vector objektum albbi felhasznlst:
void f(int n)
{
vector<X> v(n); // n darab alaprtelmezett X tpus objektum ltrehozsa
// ...
v[3] = X(99); // v[3] igazi "kezdeti rtkadsa"
// ...
}
E. Kivtelbiztossg a standard knyvtrban 1283
Nagy pazarls egy X tpus objektumot csak azrt ltrehozni, mert valamikor, ksbb rt-
ket fogunk adni neki. Klnsen nagy a vesztesg, ha az X osztlyra az rtkads kltsges
mvelet. Ezrt az X ktlpses ltrehozsa elnysnek tnhet. Az X maga is lehet egy
vector, ezrt a vector ktlpses ltrehozstl az res vektorok ltrehozsi kltsgeinek
cskkentst remlhetjk, az alaprtelmezett (res) vektorok ltrehozsa azonban mr
egybknt is elg hatkony, ezrt felesleges a megvalstst azzal bonyoltanunk, hogy az
res vektort kln esetknt kezeljk. ltalnosabban fogalmazva, a felesleges kezdeti r-
tkadsok elkerlsre ritkn jelent tkletes megoldst az, hogy a konstruktorbl kiemel-
jk az sszetettebb kezdeti rtkadsokat:
void f2(int n)
{
vector<X> v; // res vektor ltrehozsa
// ...
v.push_back(X(99)); // elemek ltrehozsa, amikor szksges
// ...
}
sszefoglalva: a ktlpses ltrehozs sokkal bonyolultabb osztlyinvarinshoz s ltal-
ban kevsb elegns, tbb hibalehetsget tartalmaz s nehezebben kezelhet program-
hoz vezet. Ezrt a nyelv ltal tmogatott konstruktor elv jobban hasznlhat, mint az
init() fggvnyes megolds". Teht az erforrsokat mindig a konstruktorban foglaljuk le,
ha a ksleltetett erforrs-lefoglalst nem teszi ktelezv maga az osztly termszete.
E.4. A szabvnyos trolk garancii
Ha a knyvtr valamelyik mvelete nmaga vlt ki kivtelt, akkor biztostani tudja s biz-
tostja is , hogy az ltala hasznlt objektumok rvnyes llapotban maradnak. A vector ese-
tben pldul az at() fggvny (16.3.3) kpes kivltani egy out_of_range kivtelt, ez azon-
ban nem jelent problmt a vektor kivtelbiztossga szempontjbl. Az at() fggvny
megrjnak nem jelent problmt, hogy a vektort rvnyes llapotba lltsa a kivtel kivl-
tsa eltt. Problmk csak akkor jelentkeznek a knyvtr megvalsti, a knyvtr fel-
hasznli, illetve azok szmra, akik megprbljk megrteni a programot , amikor fel-
hasznli eljrsok vltanak ki kivtelt.
A standard knyvtr troli alapbiztostst nyjtanak (E.2): a knyvtr alap invarinsai
mindig megmaradnak s ha a felhasznl a kvetelmnyeknek megfelelen jr el, nem ke-
letkeznek erforrs-lyukak sem. A felhasznli eljrsoktl azt kveteljk meg, hogy ne
Fggelkek s trgymutat 1284
hagyjk a trolk elemeit rvnytelen llapotban s a destruktorok ne vltsanak ki kivtelt.
Az eljrsokon most azokat a fggvnyeket rtjk, melyeket a standard knyvtr megval-
stsban felhasznlunk, teht a konstruktorokat, az rtkadsokat, a destruktorokat, illetve
a bejrk mveleteit (E.4.4).
A programoz ezeket a mveleteket knnyen megrhatja a knyvtr elvrsainak megfele-
len. A kvetelmnyeket ltalban akkor is kielgtik eljrsaink, ha nem tudatosan figye-
lnk rjuk. A kvetkez tpusok biztosan kielgtik a standard knyvtr kvetelmnyeit
a trolk elemtpusaira vonatkozan:
1. A beptett tpusok, kztk a mutatk
2. Azok a tpusok, melyek nem tartalmaznak felhasznli mveleteket
3. Az olyan mveletekkel rendelkez osztlyok, melyek nem vltanak ki kivtele-
ket s nem hagyjk operandusaikat rvnytelen llapotban
4. Azok az osztlyok, melyek destruktora nem vlt ki kivtelt, s amelyeknl
knnyen ellenrizhet, hogy a standard knyvtr ltal hasznlt eljrsok (a
konstruktorok, az rtkadsok, a <, az == s a swap() fggvny) nem hagyjk
operandusaikat rvnytelen llapotban
Azt is ellenriznnk kell minden esetben, hogy a mveletek ne hozzanak ltre erforrs-
lyukakat:
void f(Circle* pc, Triangle* pt, vector<Shape*>& v2)
{
vector<Shape*> v(10); // vektor ltrehozsa vagy bad_alloc kivtel kivltsa
v[3] = pc; // nem vlt ki kivtelt
v.insert(v.begin()+4,pt); // vagy beszrja a pt elemet, vagy nincs hatsa v-re
v2.erase(v2.begin()+3); // vagy trli v2[3]-t, vagy nincs hatsa v2-re
v2 = v; // vagy tmsolja v-t, vagy nincs hatsa v2-re
// ...
}
Amikor az f() futsa vget r, v szablyosan trldni fog, mg v2 rvnyes llapotban lesz.
A fenti rszlet nem mutatja, ki felel a pc s a pt trlsrt. Ha f() a felels, akkor vagy el kell
kapnia a kivteleket s gy kezelni a szksges trlseket, vagy a mutatkat loklis auto_ptr
vltozkhoz kell ktnie.
Ennl rdekesebb krds, mikor ad a knyvtr ers biztostst, azaz mely mveletek m-
kdnek gy, hogy vagy sikeresen futnak le, vagy semmilyen vltoztatst nem hajtanak vg-
re operandusaikon.
E. Kivtelbiztossg a standard knyvtrban 1285
Pldul:
void f(vector<X>& vx)
{
vx.insert(vx.begin()+4,X(7)); // elem hozzadsa
}
ltalban az X mveletei s a vector<X> osztly memriafoglalja vlthat ki kivtelt. Mit
mondhatunk a vx elemeirl, ha az f() fggvny futsa kivtel kvetkeztben szakad meg?
Az alapbiztosts garantlja, hogy erforrs-lyukak nem keletkeznek s a vx elemei rv-
nyes llapotban maradnak. De pontosan milyen elemekrl van sz? Elkpzelhet, hogy egy
elem azrt trldik, mert az insert() csak gy tudja az alapbiztosts kvetelmnyeit vissza-
lltani? Gyakran nem elg annyit tudnunk, hogy a trol j llapotban van, pontosan tud-
ni akarjuk azt is, milyen llapotrl van sz. A kivtel kezelse utn ltalban tisztban sze-
retnnk lenni azzal, hogy milyen elemek szerepelnek a vektorban, mert ellenkez esetben
komolyabb hibakezelst kellene vgeznnk.
E.4.1. Elemek beszrsa s trlse
Az elemek beszrsa egy trolba, illetve az elemek trlse onnan nyilvnval pldja azon
mveleteknek, melyek a trolt megjsolhatatlan llapotban hagyhatnk egy kivtel bek-
vetkezsekor. Ennek oka leginkbb az, hogy a beszrs s a trls sorn sok olyan mve-
letet hajtunk vgre, amely kivtelt vlthat ki:
1. j rtket msolunk a trolba.
2. A trolbl eltvoltott elemet meg is kell semmistennk.
3. Az j elem trolshoz nha memrit is kell foglalnunk.
4. A vector s a deque elemeit nha j helyre kell thelyeznnk.
5. Az asszociatv trolk sszehasonlt eljrsokat alkalmaznak az elemekre.
6. Sok beszrs s trls esetben bejr mveleteket is vgre kell hajtanunk.
Ezek a mveletek mind okozhatnak kivteleket, ezt semmilyen biztosts (E.2) nem aka-
dlyozza meg. Ahhoz, hogy ezekre az esetekre valamilyen biztostst nyjtsunk, elviselhe-
tetlenl kltsges eljrsokra lenne szksg. Ennek ellenre a knyvtr vdi magt s
a felhasznlkat a tbbi, felhasznli fggvny kivteleitl.
Amikor lncolt adatszerkezeteken vgznk mveleteket (pldul egy list-en vagy map-en),
gy szrhatunk be s tvolthatunk el elemeket, hogy a trol tbbi elemre nem vagyunk
Fggelkek s trgymutat 1286
hatssal. Ugyanez nem valsthat meg az olyan trolkban, ahol tbb elem szmra egyet-
len, folytonos memriaterletet foglalunk le (pldul a vector s a deque esetben). Ilyen-
kor az elemeket nha j helyre kell mozgatnunk.
Az alapbiztostson tl a standard knyvtr ers biztostst is nyjt nhny olyan mvelet-
hez, amely elemeket szr be vagy trl. Mivel a lncolt adatszerkezetekkel megvalsthat
trolk ebbl a szempontbl jelentsen eltrnek az elemek trolshoz folytonos memria-
terletet hasznlktl, a standard knyvtr teljesen ms garancikat ad a klnbz
trolfajtkhoz:
1. Garancik a vector (16.3) s a deque (17.2.3) osztlyra:
Ha egy push_back() vagy egy push_front() mvelet okoz kivtelt, akkor az
nem vltoztatja meg operandusait.
Ha egy insert() utasts vlt ki kivtelt s azt nem egy elem msol
konstruktora vagy rtkad mvelete okozta, akkor az sem vltoztat
operandusain.
Az erase() mvelet csak akkor vlt ki kivtelt, ha azt az elemek msol
konstruktora vagy rtkad mvelete okozza.
A pop_back() s a pop_front() nem okoz kivtelt.
2. A list (17.2.2) garancii:
Ha egy push_back() vagy push_front() mvelet vlt ki kivtelt, akkor a fgg-
vny hatstalan.
Ha az insert() okoz kivtelt, akkor az nem vltoztatja meg operandusait.
Az erase(), a pop_back(), a pop_front(), a splice() s a reverse() sohasem vlt
ki kivtelt.
Ha a prediktumok s az sszehasonlt fggvnyek nem okoznak kivtelt,
akkor a list osztly remove(), remove_if(), unique(), sort() s merge() eljr-
sai sem vlthatnak ki kivtelt.
3. Garancik asszociatv trolkra (17.4):
Ha egy elem beszrsa kzben az insert() kivtelt vlt ki, akkor a fggvny
hatstalan.
Az erase() nem okozhat kivtelt.
Jegyezzk meg, hogy ha ers biztosts ll rendelkezsnkre egy trol valamelyik mve-
letben, akkor minden bejr, az elemekre hivatkoz sszes mutat s hivatkozs (referen-
cia) rvnyes marad kivtel bekvetkezse esetn is.
A szablyokat egy tblzatban foglalhatjuk ssze:
E. Kivtelbiztossg a standard knyvtrban 1287
Fggelkek s trgymutat 1288
A trolmveletek garancii
vector deque list map
clear() nem lehet kivtel nem lehet kivtel nem lehet kivtel nem lehet kivtel
(msols) (msols)
erase() nem lehet kivtel nem lehet kivtel nem lehet kivtel nem lehet kivtel
(msols) (msols)
1 elem insert() ers ers ers ers
(msols) (msols)
N elem insert() ers ers ers alap
(msols) (msols)
merge() nem lehet kivtel
(sszehasonlts)
push_back() ers ers ers
push_front() ers ers
pop_back() nem lehet kivtel nem lehet kivtel nem lehet kivtel
pop_front() nem lehet kivtel nem lehet kivtel
remove() nem lehet kivtel
(sszehasonlts)
remove_if() nem lehet kivtel
(prediktum)
reverse() nem lehet kivtel
splice() nem lehet kivtel
swap() nem lehet kivtel nem lehet kivtel nem lehet kivtel nem lehet kivtel
(sszehasonlts
msolsa)
unique() nem lehet kivtel
(sszehasonlts)
A tblzat elemeinek jelentse:
alap A mvelet csak alapbiztostst nyjt (E.2).
ers A mvelet ers biztostst nyjt (E.2).
nem lehet kivtel A mvelet nem vlthat ki kivtelt (E.2).
A mvelet ebben a trolban nem szerepel tagfggvnyknt.
Ahol a biztosts megkveteli, hogy a felhasznl ltal megadott bizonyos mveletek ne
vltsanak ki kivtelt, ott a biztosts alatt zrjelben feltntettk, milyen mveletekre kell fi-
gyelnnk. Ezek a kvetelmnyek pontosan megegyeznek a tblzat eltt, szvegesen meg-
fogalmazott felttelekkel.
A swap() fggvnyek abban klnbznek a tbbi eljrstl, hogy nem tagfggvnyek.
A clear() fggvnyre vonatkoz garancia az erase() biztostsbl kvetkezik. (16.3.6)
A tblzatban az alapbiztostson tli szolgltatsokat tntettk fel, teht nem szerepelnek
azok az eljrsok (pldul a reverse() vagy a unique() a vector osztlyra), melyek tovbbi
biztosts nlkl valstanak meg valamilyen algoritmust az sszes sorozatra.
A majdnem-trol basic_string (17.5, 20.3) minden mveletre garantlja az alapbiztos-
tst (E.5.1). A szabvny azt is biztostja, hogy a basic_string osztly erase() s swap() eljr-
sa nem okoz kivtelt, az insert() s a push_back() fggvnyre pedig ers biztostst kapunk.
Az ers biztostst nyjt eljrsokban amellett, hogy a trol vltozatlan marad, az sszes
bejr, mutat s referencia is rvnyes marad:
void update(map<string,X>& m, map<string,X>::iterator current)
{
X x;
string s;
while (cin>>s>>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 lehetsgekkel ma-
gyarzhatk. A programozk azt szeretnk leginkbb, hogy mindenhol ers biztosts ll-
jon rendelkezskre a lehet legkevesebb korltozs mellett, de ugyanakkor azt is elvrjk,
hogy a standard knyvtr minden mvelete optimlisan hatkony legyen. Mindkt elvrs
jogos, de sok mvelet 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 elszr, hogy egy elemet hogyan vihetnk be egy listba vagy egy vektorba. Szo-
ks szerint, a push_back() nyjtja a legegyszerbb lehetsget:
void f(list<X>& lst, vector<X>& 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 rtk j elemmel rendelkezik
}
Az ers biztosts megvalstsa ez esetben egyszer 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 t-
rol 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() mveletnek gyakran kell egy elemet a trol kzepn elhelyeznie. Lncolt adat-
szerkezeteknl ez nem jelent problmt, teht a list s a map egyszeren megvalsthat,
a vector esetben azonban elre lefoglalt terlet ll rendelkezsnkre, a vector<X>::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 egyszer md-
Fggelkek s trgymutat 1290
szer, hogy a vektort visszalltsuk eredeti llapotba, ha valamelyik elem msol rtkad-
sa vagy msol konstruktora kivtelt vlt ki (lsd E.8[10-11]), ezrt a vector azzal a felttel-
lel 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<X>& lst, vector<X>& vec, map<string,X>& 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 rtk j elemmel rendelkezik
// m egy j (s,x) rtk elemmel rendelkezik
}
Ha X::cannot_copy kivtelt kapunk, nem tudhatjuk, hogy az j elem bekerlt-e a vec tro-
lba. Ha sikerlt beilleszteni az elemet, az rvnyes llapotban lesz, de pontos rtkt nem
ismerjk. Az is elkpzelhet, hogy egy X::cannot_copy kivtel utn nhny elem titokza-
E. Kivtelbiztossg a standard knyvtrban 1291
tosan megkettzdik (lsd E.8[11]), msik megvalstst alkalmazva pedig a vektor vgn
lv elemek tnhetnek el, mert csak gy lehet biztostani, hogy a trol rvnyes llapotban
maradjon s ne szerepeljenek benne rvnytelen elemek.
Sajnos az ers biztosts megvalstsa a vector osztly insert() fggvnye esetben lehetet-
len, ha megengedjk, hogy az elemek msol konstruktora kivtelt vltson ki. Ha egy vek-
torban teljesen meg akarnnk vdeni magunkat az elemek thelyezse kzben keletkez
kivtelektl, a kltsgek elviselhetetlenl megnnnek az egyszer, alapbiztostst nyjt
megoldshoz kpest.
Sajnos nem ritkk az olyan elemtpusok, melyek msol konstruktora kivtelt eredmnyez-
het. Mr a standard knyvtrban is tallhatunk pldt: a vector<string>, a vector<
vector<double> > s a map<string, int> is ilyen.
A list s a vector trol ugyanolyan biztostst ad az insert() egyelem s tbbelem vlto-
zathoz, mert azok megvalstsi mdja azonos. A map viszont ers biztostst ad az egy-
elem beszrshoz, mg a tbbelemhz csak alapbiztostst. Az egyelem insert() a map
esetben knnyen elkszthet ers biztostssal, a tbbelem vltozat egyetlen logikus
megvalstsi mdja azonban a map esetben az, hogy az j elemeket egyms utn szrjuk
be, s ehhez mr nagyon nehz lenne ers garancikat adni. A gondot itt az jelenti, hogy
nincs egyszer visszalpsi lehetsg (nem tudunk korbbi sikeres beszrsokat visszavon-
ni), ha valamelyik elem beszrsa nem sikerl.
Ha olyan tbbelem beszr mveletre van szksgnk, amely ers biztostst ad, azaz
vagy minden elemet hibtlanul beilleszt, vagy egyltaln nem vltoztatja meg a trolt, leg-
egyszerbben gy valsthatjuk meg, hogy egy teljesen j trolt ksztnk, majd ennek si-
keres ltrehozsa utn egy swap() mveletet alkalmazunk:
template<class C, class Iter>
void safe_insert(C& c, typename C::const_iterator i, Iter begin, Iter end)
{
C tmp(c.begin(),i); // az ell lev 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.
Fggelkek s trgymutat 1292
E.4.3. A swap()
A msol konstruktorokhoz s rtkadsokhoz hasonlan a swap() eljrsok is nagyon fon-
tos 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 szerepl rtkeket
cserlgeti, akkor a trol elemei a csere helyett vagy vltozatlanok maradnak, vagy megket-
tzdnek.
Vizsgljuk meg a standard knyvtr swap() fggvnynek albbi, egyszer megvalstst
(18.6.8):
template<class T> 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() fgg-
vny 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 mozgat-
nunk, azok konstruktorra vagy rtkad mveletre nincs szksgnk, teht azok nem
kapnak lehetsget 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 kivte-
lek 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 m-
sol konstruktorbl vagy rtkad mveletbl szrmazik (17.1.4.1). Szerencsre az
sszehasonlt objektumoknak ltalban annyira egyszer msol mveleteik vannak,
hogy nincs lehetsgk kivtel kivltsra.
A felhasznli swap() fggvnyek viszonylag egyszeren nyjthatnak ugyanilyen biztost-
sokat, ha gondolunk r, hogy mutatkkal brzolt adatok esetben elegend csak a mu-
tatkat 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 alapve-
t rsze minden trolnak (E.3). Ebbl kvetkezik, hogy a fel nem tlttt (elksztetlen)
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 ers
biztostst valstanak meg (E.2), amihez gyakran kell elemeket trlni, teht az a kvetel-
mny, miszerint a destruktoroknak tilos kivtelt kivltaniuk, elengedhetetlen ezeknl
a fggvnyeknl is (lsd E.8[14]). Ezenkvl azoknak a bejrknak is megfelelen kell vi-
selkednik, melyeket paramterknt adunk t ezeknek az eljrsoknak. Teht rvnyes be-
jrknak kell lennik, rvnyes sorozatokra kell hivatkozniuk, s a bejr mveleteknek
(pldul a ++, a != vagy a * opertornak) nem szabad kivtelt kivltaniuk, ha rvnyes be-
jrkra alkalmazzuk azokat.
A bejrk (itertorok) olyan objektumok, melyeket a szabvnyos algoritmusok s a szabv-
nyos trolk mveletei szabadon lemsolhatnak, teht ezek msol konstruktora s mso-
l rtkadsa nem eredmnyezhet kivtelt. A szabvny garantlja, hogy a szabvnyos tro-
lk ltal visszaadott bejrk msol konstruktora s msol rtkadsa nem vlt ki kivtelt,
gy a vector<T>::begin() ltal visszaadott bejrt pldul nyugodtan lemsolhatjuk, nem kell
kivteltl tartanunk.
Figyeljnk r, hogy a bejrkra alkalmazott ++ vagy -- mvelet eredmnyezhet kivtelt. Pl-
dul egy istreambuf_iterator (19.2.6) egy bemenethibt (logikusan) egy kivtel kivlts-
val jelezhet, egy tartomnyellenrztt 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 elemrl a m-
sikra, 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 -- mvelet nem okoz kivtelt. Ha ezt mgis megteszik, a szab-
vny megfogalmazsa szerint ezek nem is igazn bejrk, vagy az ltaluk megadott soro-
zat nem rtelmezhet sorozatknt. Most is igaz, hogy a szabvny nem kpes megvdeni
a felhasznlt a sajt maga ltal okozott nem meghatrozhat viselkedstl (E.2).
E.4.5. Hivatkozsok elemekre
Ha elemre hivatkoz mutatt, referencit vagy bejrt adunk t egy eljrsnak, az tnkre-
teheti a listt azzal, hogy az adott elemet rvnytelenn teszi:
Fggelkek s trgymutat 1294
void f(const X& x)
{
list<X> lst;
lst.push_back(x);
list<X>::iterator i = lst.begin();
*i = x; // x listba msolsa
// ...
}
Ha az x vltozban rvnytelen rtk szerepel, a list destruktora nem kpes hibtlanul meg-
semmisteni az lst objektumot:
struct X {
int* p;
X() { p = new int; }
~X() { delete p; }
// ...
};
void malicious()
{
X x;
x.p = reinterpret_cast<int*>(7); // hibs x
f(x); // idztett bomba
}
Az f() vgrehajtsnak befejeztvel meghvdik a list<X> destruktora, amely viszont meg-
hvja az X destruktort egy rvnytelen rtkre. Ha megprbljuk a delete p parancsot vg-
rehajtani egy olyan p rtkre, amely nem 0 s nem is ltez X tpus rtkre mutat, az ered-
mny nem meghatrozhat lesz s akr a rendszer azonnali sszeomlst okozhatja. Egy
msik lehetsg, hogy a memria rvnytelen llapotba kerl, ami sokkal ksbb, a prog-
ram olyan rszben okoz megmagyarzhatatlan hibkat, amely teljesen fggetlen a tny-
leges problmtl.
Ez a hibalehetsg nem gtolja meg a programozkat abban, hogy referencikat s bejr-
kat hasznljanak a trolk elemeinek kezelsre, hiszen mindenkppen ez az egyik legegy-
szerbb s leghatkonyabb mdszer az ilyen feladatok elvgzshez. Mindenesetre rde-
mes klnsen elvigyzatosnak lennnk a trolk elemeire val hivatkozsokkal
kapcsolatban. Ha egy trol psge veszlybe kerlhet, rdemes a kevsb gyakorlott fel-
hasznlk szmra biztonsgosabb, ellenrztt vltozatokat is ksztennk, pldul megad-
hatunk egy olyan eljrst, amely ellenrzi, hogy az j elem rvnyes-e, mieltt beszrja azt
a fontos trolba. Termszetesen ilyen ellenrzseket csak akkor vgezhetnk, ha ponto-
san ismerjk a trolban trolt elemek tpust.
E. Kivtelbiztossg a standard knyvtrban 1295
ltalban, ha egy trol valamelyik eleme rvnytelenn vlik, a trolra alkalmazott min-
den tovbbi mvelet hibkat eredmnyezhet. Ez nem csak a trolk sajtja: brmely objek-
tum, amely valamilyen szempontbl hibs llapotba kerl, a ksbbiekben brmikor okoz-
hat problmkat.
E.4.6. Prediktumok
Szmos szabvnyos algoritmus s trol hasznl olyan prediktumokat, melyeket a felhasz-
nlk adhatnak meg. Az asszociatv trolk esetben ezek klnsen fontos szerepet tlte-
nek be: az elemek keresse s beszrsa is ezen alapul.
A szabvnyos trolk mveletei ltal hasznlt prediktumok is okozhatnak kivteleket, s
ha ez bekvetkezik, a standard knyvtr mveletei legalbb alapbiztostst nyjtanak, de
sok esetben (pldul az egyelem insert() mveletnl) ers biztosts ll rendelkezsnk-
re (E.4.1). Ha egy troljn vgzett mvelet kzben egy prediktum kivtelt vlt ki, elkp-
zelhet, 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)
mvelet vgrehajtsa kzben, nem vrhatjuk el, hogy minden rtkismtlds eltnjn.
A felhasznl mindssze annyit felttelezhet, hogy a listban szerepl rtkek rvnyesek
maradnak (lsd E.5.3).
Szerencsre a prediktumok ritkn csinlnak olyasmit, ami kivtelt eredmnyezhet. Ennek
ellenre a felhasznli <, ==, s != prediktumokat figyelembe kell vennnk, amikor kiv-
telbiztossgrl beszlnk.
Az asszociatv trolk sszehasonlt objektumairl a swap() mvelet vgrehajtsa sorn
msolat kszl (E.4.3), ezrt rdemes biztostanunk, hogy azon prediktumok msol m-
veletei, melyeket felhasznlhatunk sszehasonlt objektumokknt, ne vlthassanak ki
kivtelt.
E.5. A standard knyvtr tovbbi rszei
A kivtelbiztossg legfontosabb clja, hogy fenntartsuk az objektumok psgt s kvetke-
zetessgt, azaz az nll objektumok alap-invarinsa mindig igaz maradjon s az egyms-
sal kapcsolatban ll objektumok se srljenek. A standard knyvtr szemszgbl nzve
Fggelkek s trgymutat 1296
a kivtelbiztossg fenntartsa a trolk esetben a legbonyolultabb. Ha a kivtelbiztossg-
ra sszpontostunk, a standard knyvtr tbbi rsze nem tl rdekes, de a kivtelbiztossg
szempontjbl a beptett tmb is egy trol, melyet feleltlen mveletekkel knnyen
tnkretehetnk.
A standard knyvtr fggvnyei ltalban csak olyan kivteleket vlthatnak ki, melyeket
meghatroznak vagy amelyeket az ltaluk meghvott felhasznli mveletek eredmnyez-
hetnek. Emellett azok az eljrsok, melyek (kzvetve vagy kzvetlenl) memrit foglalnak
le, a memria elfogyst kivtellel jelezhetik (ltalban az std::bad_alloc kivtellel).
E.5.1. Karakterlncok
A string objektumokon vgzett mveletek sokfle kivtelt okozhatnak, a basic_string vi-
szont karaktereit a char_traits (20.2) osztly ltal biztostott fggvnyekkel kezeli s ezek-
nek nem szabad kivtelt okozniuk. A standard knyvtr char_traits objektumai nem vlta-
nak ki kivteleket, s ha egy felhasznli char_traits valamelyik eljrsa eredmnyez ilyet,
azrt a standard knyvtr semmilyen felelssget nem vllal. Klnsen fontos, hogy
a basic_string osztlyban elemknt (karakterknt) hasznlt tpus nem rendelkezhet felhasz-
nli msol konstruktorral s rtkadssal, mert gy nagyon sok kivtel-lehetsgtl sza-
badulunk meg.
A basic_string nagyon hasonlt a szabvnyos trolkra (17.5, 20.3), elemei valjban egy
egyszer sorozatot alkotnak, melyet a basic_string<Ch,Tr,A>::iterator vagy
a basic_string<Ch,Tr,A>::const_iterator objektumokkal rhetnk el. Ennek kvetkeztben
a string alapbiztostst (E.2) ad s az erase(), az insert(), a push_back() s a swap() (E.4.1)
fggvny garancii a basic_string osztly esetben is rvnyesek.
A basic_string<Ch,Tr,A>::push_back() pldul ers biztostst nyjt.
E.5.2. Adatfolyamok
Ha egy adatfolyamot megfelelen lltunk be, annak fggvnyei az llapotvltozsokat ki-
vtelekkel jelzik (21.3.6). Ezek jelentse pontosan meghatrozott s nem okoznak
kivtelbiztossgi problmkat. Ha egy felhasznli operator<<() vagy operator>>() eljrs
okoz kivtelt, az gy jelenhet meg a programoz szmra, mintha azt az iostream knyvtr
okozta volna. Ennek ellenre ezek a kivtelek nem hatnak az adatfolyam llapotra
(21.3.3). Az adatfolyam ksbbi mveletei esetleg nem talljk meg az ltaluk vrt adato-
kat mert egy korbbi mvelet kivtelt vltott ki a szablyos befejezds helyett , de ma-
E. Kivtelbiztossg a standard knyvtrban 1297
ga az adatfolyam nem vlik rvnytelenn. Szoks szerint az I/O problmk utn szksg
lehet a clear() fggvny meghvsra, mieltt tovbbi rst vagy olvasst kezdemnyeznnk
(21.3.3, 21.3.5).
A basic_string osztlyhoz hasonlan az iostream is egy char_traits objektumra hivatkozik
a karakterkezels megvalstshoz (20.2.1, E.5.1), teht felttelezheti, hogy a karaktere-
ken vgzett mveletek nem okoznak kivtelt, illetve semmilyen biztostst nem kell adnia,
ha a felhasznl megsrti ezt a kiktst.
Ahhoz, hogy a standard knyvtr kellen hatkony optimalizlst alkalmazhasson, feltte-
lezzk, hogy a locale (D.2) s a facet (D.3) objektumok sem okozhatnak kivtelt. Ha mg-
is gy mkdnek, akkor az azokat hasznl adatfolyamok rvnytelenn vlhatnak. Ennek
ellenre a leggyakoribb ilyen kivtel az std::bad_cast a use_facet (D.3.1) fggvnyben
csak olyan, felhasznl ltal rt programrszletekben fordul el, melyek fggetlenek a szab-
vnyos adatfolyamoktl, gy a legrosszabb esetben is csak a kirs flbeszakadst vagy hi-
bs beolvasst eredmnyez, az adatfolyam (legyen az akr istream, akr ostream) rvnyes
marad.
E.5.3. Algoritmusok
Eltekintve az uninitialized_copy(), az uninitialized_fill() s az uninitialized_fill_n() fgg-
vnytl (E.4.4) a standard knyvtr az algoritmusokhoz alapbiztostst (E.2) ad. Ez azt je-
lenti, hogy ha a felhasznl ltal megadott objektumok a kvetelmnyeknek megfelelen
viselkednek, az algoritmusok fenntartjk a standard knyvtr invarinsait s elkerlik az
erforrs-lyukakat. A nem meghatrozott viselkeds elkerlse rdekben a felhasznli
mveleteknek mindig rvnyes llapotban kell hagyniuk paramtereiket s
a destruktoroknak nem szabad kivteleket kivltaniuk.
Az algoritmusok maguk nem okoznak kivteleket, ehelyett visszatrsi rtkkn keresz-
tl jelzik a problmkat. A keres algoritmusok pldul tbbnyire a sorozat vgt adjk
vissza annak jelzsre, hogy nem talltk meg a keresett elemet (18.2). Teht a szabvnyos
algoritmusokban keletkez kivtelek valjban mindig egy felhasznli eljrsbl szrmaz-
nak. Ez azt jelenti, hogy a kivtel vagy az egyik elemen vgzett mvelet prediktum
(18.4), rtkads vagy swap() kzben jtt ltre, vagy egy memriafoglal (19.4) okozta.
Ha egy ilyen mvelet kivtelt okoz, az algoritmusok azonnal befejezik mkdsket s az
algoritmust elindt fggvny feladata lesz, hogy a kivtelt kezelje. Nhny algoritmus ese-
tben elfordulhat, hogy a kivtel akkor kvetkezik be, amikor a trol llapota a felhasz-
nl szempontjbl elfogadhatatlan. Nhny rendez eljrs pldul az elemeket ideigle-
Fggelkek s trgymutat 1298
nesen egy tmeneti trba msolja s ksbb innen teszi azokat vissza az eredeti trolba.
Egy ilyen sort() eljrs esetleg sikeresen kimsolja az elemeket a trolbl (azt tervezve,
hogy hamarosan a megfelel sorrendben rja azokat vissza), helyesen vgzi el a trlst is,
de ezutn azonnal kivtel kvetkezik be. A felhasznl szempontjbl a trol teljesen
megsemmisl, ennek ellenre minden elem rvnyes llapotban van, teht az alapbiztos-
ts megvalstsa egyszer feladat.
Gondoljunk r, hogy a szabvnyos algoritmusok a sorozatokat bejrkon keresztl rik el,
sohasem kzvetlenl a trolkon dolgoznak, hanem azok elemein. A tny, hogy ezek az al-
goritmusok soha nem kzvetlenl vesznek fel elemeket egy trolba vagy trlnek eleme-
ket onnan, leegyszersti annak vizsglatt, hogy egy kivtelnek milyen kvetkezmnyei le-
hetnek. Ha egy adatszerkezetet csak konstans bejrkon, mutatkon vagy referencikon
(pldul const Rec*) keresztl rhetnk el, ltalban nagyon egyszeren ellenrizhetjk,
hogy a kivtelek mvelnek-e valamilyen veszlyes dolgot.
E.5.4. A valarray s a complex
A szmkezel fggvnyek sem okoznak kifejezetten kivteleket (22. fejezet), de a valarray
osztlynak memrit kell foglalnia, gy hasznlatakor elfordulhat std::bad_alloc kivtel.
Ezenkvl a valarray s a complex kaphat olyan elemtpust is (skalrokat), amely kivtele-
ket vlthat ki. Szoks szerint a szabvny alapbiztostst (E.2) nyjt, de a kivtelek ltal meg-
szakadt szmtsok eredmnyrl semmit sem felttelezhetnk.
A basic_string osztlyhoz hasonlan (E.5.1) a valarray s a complex is felttelezheti, hogy
a sablonparamterben megadott tpus nem rendelkezik felhasznli msol mveletek-
kel, teht egyszeren, bjtonknt msolhat. A standard knyvtr numerikus tpusainak
tbbsge a sebessgre optimalizlt, gy felttelezi, hogy elemtpusai nem okoznak kivtele-
ket.
E.5.5. A C standard knyvtra
A standard knyvtr kivtel-meghatrozs nlkli mveletei az adott C++-vltozattl fgg-
en vlthatnak ki kivteleket, a C standard knyvtrnak fggvnyeinl azonban biztosak le-
hetnk abban, hogy csak akkor okoznak kivteleket, ha a nekik paramterknt tadott el-
jrsok kivtelt okoznak, hiszen vgeredmnyben ezeket a fggvnyeket C programok is
hasznljk s a C-ben nincsenek kivtelek. Egy szp megvalsts a szabvnyos C fggv-
nyeket res kivtel-meghatrozssal adhatja meg (throw()), ezzel lehetsget adhat a for-
dtnak jobb kd ellltsra.
E. Kivtelbiztossg a standard knyvtrban 1299
Az olyan fggvnyek, mint a qsort() vagy a bsearch(), egy fggvnyre hivatkoz mutatt
vesznek t paramterknt, gy okozhatnak kivtelt, ha paramterk kpes erre. Az alapbiz-
tosts (E.2) ezekre a fggvnyekre is kiterjed.
E.6. Javaslatok a knyvtr felhasznli szmra
A standard knyvtr vizsglatakor a kivtelbiztossgra gy tekinthetnk, mint egy probl-
mamentest eszkzre, amely sok mindentl megvd minket, ha nem okozunk sajt ma-
gunknak kellemetlensgeket. A knyvtr mindaddig helyesen fog mkdni, amg a felhasz-
nli eljrsok teljestik az alapkvetelmnyeket (E.2). A szabvnyos trolk mveletei
ltal kivltott kivtelek tbbnyire nem okoznak memria-elszivrgst s a trolt rvnyes
llapotban hagyjk. Teht a knyvtr hasznlinak a legfontosabb krds a kvetkez: ho-
gyan hatrozzuk meg sajt tpusainkat ahhoz, hogy elkerljk a kiszmthatatlan viselke-
dst s a memria-lyukak keletkezst?
Az alapszablyok a kvetkezk:
1. Amikor egy objektumot frisstnk, soha ne mdostsuk az eredeti brzolst ad-
dig, amg az j rtket teljesen ltre nem hoztuk s nem biztostottuk, hogy ki-
vtel veszlye nlkl le tudjuk cserlni az rtket. Pldakppen nzzk meg
a vector::operator=(), a safe_assign() vagy a vector::push_back() fggvny meg-
valstst az E.3 pontban.
2. Mieltt kivtelt vltunk ki, szabadtsunk fel minden olyan lefoglalt erforrst,
amelyet nem ktttnk (ms) objektumhoz.
2a A kezdeti rtkads az erforrs megszerzsvel mdszer (14.4) s
a nyelv szablyai, melyek szerint a rszben ltrehozott objektumok olyan
mrtkben trldnek, amennyire ltrejttek (14.4.1), nagyban elsegtik ezt
a clt. Pldakppen nzzk meg a leak() fggvnyt. (E.2).
2b Az uninitialized_copy() s testvrei automatikus erforrs-felszabadtst
tesznek lehetv, ha egy objektumhalmaz ltrehozsa nem sikerl (E.4.4).
3. Mieltt kivtelt vltunk ki, ellenrizzk, hogy minden operandus rvnyes lla-
potban van-e, azaz minden objektumot olyan llapotban kell hagynunk, hogy
az ksbb szablyosan elrhet s trlhet legyen anlkl, hogy nem megha-
trozhat eredmnyeket kapnnk s a destruktornak kivtelt kellene kivltania.
Pldakppen a vector rtkadst emlthetjk (E.3.2).
Fggelkek s trgymutat 1300
3a A konstruktorok abban is eltrnek az tlagos eljrsoktl, hogy ha ezekben
keletkezik kivtel, nem jn ltre objektum, amelyet ksbb trlnnk kelle-
ne. Ebbl kvetkezik, hogy ha egy konstruktorban kell kivtelt kivltanunk,
akkor nem kell invarinst helyrelltanunk, de minden erforrst fel kell sza-
badtanunk, amit a konstruktor megszakadsa eltt lefoglaltunk.
3b A destruktorok abban klnbznek a tbbi mvelettl, hogy ha itt kivtel
keletkezik, szinte biztosan elrontunk valamilyen invarinst s akr
a terminate() fggvny azonnali meghvst is elidzhetjk.
A gyakorlatban ezeket a szablyokat meglepen nehz betartani. Ennek legfbb oka az,
hogy a kivtelek gyakran ott kvetkeznek be, ahol egyltaln nem vrjuk azokat. Egy j pl-
da erre az std::bad_alloc. Brmely fggvny okozhatja ezt a kivtelt, amely kzvetve vagy
kzvetlenl hasznlja a new opertort vagy egy allocator objektumot memria lefoglals-
hoz. Bizonyos programokban ezt a hibt elkerlhetjk, ha nem ignylnk a lehetsgesnl
tbb memrit, az olyan programok esetben azonban, amelyek elg sokig futnak vagy je-
lents mennyisg adatot kell feldolgozniuk, fel kell kszlnnk a legklnbzbb hibkra
az erforrs-foglalsokkal kapcsolatban. Ez azt jelenti, hogy feltteleznnk kell, hogy min-
den fggvny kpes brmely kivtel kivltsra, amg mst nem bizonytottunk rjuk.
A meglepetsek elkerlsnek egyik mdja az, hogy csak olyan elemekbl ptnk trol-
kat, melyek nem hasznlnak kivteleket (pldul mutatkbl vagy egyszer, konkrt tpu-
sokbl) vagy lncolt trolkat (pldul list) hasznlunk, melyek ers biztostst nyjtanak
(E.4). A msik, ellenttes megkzelts, hogy elssorban az olyan mveletekre szmtunk,
melyek ers biztostst nyjtanak (pldul a push_back()). Ezek vagy sikeresen befejezd-
nek, vagy egyltaln nincs hatsuk (E.2), de nmagukban nem elegendek az erforrs-
lyukak elkerlsre s csak rendezetlen, pesszimista hibakezelst s helyrelltst tesznek
lehetv. A vector<T*> pldul tpusbiztos, ha a T tpuson vgzett mveletek nem okoznak
kivteleket, de ha kivtel kvetkezik be a vector objektumban s nem gondoskodunk vala-
hol a mutatott objektumok trlsrl, azonnal memria-lyukak keletkeznek. Ebbl kvet-
kezik, hogy be kell vezetnnk egy Handle osztlyt, amely mindig elvgzi a szksges fel-
szabadtsokat (25.7), s az egyszer vector<T*> helyett a vector< Handle<T> > szerkezetet
kell hasznlnunk. Ez a megolds az egsz programot rugalmasabb teszi.
Amikor j programot ksztnk, lehetsgnk van arra, hogy tgondoltabb megkzeltst
talljunk s biztostsuk, hogy erforrsainkat olyan osztlyokkal brzoljuk, melyek invari-
nsa alapbiztostst nyjt (E.2). Egy ilyen rendszerben lehetsg nylik arra, hogy kiv-
lasszuk a ltfontossg objektumokat s ezek mveleteihez visszagrgetsi mdszereket al-
kalmazzunk (azaz ers biztostst adhatunk nhny egyedi felttel mellett).
E. Kivtelbiztossg a standard knyvtrban 1301
A legtbb program tartalmaz olyan adatszerkezeteket s programrszeket, melyeket a kiv-
telbiztossgra nem gondolva rtak meg. Ha szksg van r, ezek a rszek egy kivtelbiztos
keretbe gyazhatk. Az egyik lehetsg, hogy biztostjuk, hogy kivtelek ne kvetkezzenek
be (ez trtnt a C standard knyvtrval, E.5.5), a msik megolds pedig az, hogy fellet-
osztlyokat hasznlunk, melyekben a kivtelek viselkedse s az erforrsok kezelse pon-
tosan meghatrozhat.
Amikor olyan j tpusokat terveznk, amelyek kivtelbiztos krnyezetben futnak majd, k-
ln figyelmet kell szentelnnk azoknak az eljrsoknak, melyeket a standard knyvtr
hasznlni fog: a konstruktoroknak, a destruktoroknak, az rtkadsoknak, sszehasonlt-
soknak, swap fggvnyeknek, a prediktumknt hasznlt fggvnyeknek s a bejrkat ke-
zel eljrsoknak. Ezt legknnyebben gy valsthatjuk meg, hogy egy j osztlyinvarinst
hatrozunk meg, amelyet minden konstruktor knnyedn biztosthat. Nha gy kell meg-
terveznnk az osztlyinvarinst, hogy az objektumoknak legyen egy olyan llapota, mely-
ben egyszeren trlhetk, ha egy mvelet kellemetlen helyen tkzik hibba. Idelis
esetben ez az llapot nem egy mestersgesen megadott rtk, amit csak a kivtelkezels mi-
att kellett bevezetni, hanem az osztly termszetbl kvetkez llapot (E.3.5).
Amikor kivtelbiztossggal foglalkozunk, a f hangslyt az objektumok rvnyes llapotai-
nak (invarinsainak) meghatrozsra s az erforrsok megfelel felszabadtsra kell he-
lyeznnk. Ezrt nagyon fontos, hogy az erforrsokat kzvetlenl osztlyokkal brzoljuk.
A vector_base (E.3.2) ennek egyszer pldja. Az ilyen erforrs-osztlyok konstruktora ala-
csonyszint erforrsokat foglal le (pldul egy memriatartomnyt a vector_base esetben),
s invarinsokat llt be (pldul a mutatkat a megfelel helyekre lltja a vector_base osz-
tlyban). Ezen osztlyok destruktora egyszeren felszabadtja a lefoglalt erforrst. A rszle-
ges ltrehozs szablyai (14.4.1) s a kezdeti rtkads az erforrs lefoglalsval md-
szer (14.4) alkalmazsa lehetv teszi, hogy az erforrsokat gy kezeljk.
Egy jl megrt konstruktor minden objektum esetben belltja a megfelel invarinst
(24.3.7.1), teht a konstruktor olyan rtket ad az objektumnak, amely lehetv teszi, hogy
a tovbbi mveleteket egyszeren meg tudjuk rni s sikeresen vgre tudjuk hajtani. Ebbl
kvetkezik, hogy a konstruktoroknak gyakran kell erforrst lefoglalniuk. Ha ezt nem tud-
jk elvgezni, kivtelt vlthatnak ki, gy az objektum ltrehozsa eltt foglalkozhatunk a je-
lentkez problmkkal. Ezt a megkzeltst a nyelv s a standard knyvtr kzvetlenl t-
mogatja (E.3.5).
Az a kvetelmny, hogy az erforrsokat fel kell szabadtanunk s az operandusokat rv-
nyes llapotban kell hagynunk a kivtel kivltsa eltt, azt jelenti, hogy a kivtelkezels ter-
heit megosztjuk a kivtelt kivlt fggvny, a hvsi lncban lev fggvnyek s a kivtelt
tnylegesen kezel eljrs kztt. Egy kivtel kivltsa nem azt a hibakezelsi stlust jelen-
Fggelkek s trgymutat 1302
ti, hogy hagyjuk az egszet valaki msra. Minden fggvnynek, amely kivtelt vlt ki vagy
ad tovbb, ktelessge felszabadtani azokat az erforrsokat, melyek hatskrbe tartoz-
nak, operandusait pedig megfelel rtkre kell lltania. Ha az eljrsok ezt a feladatot nem
kpesek vgrehajtani, a kivtelkezel nemigen tehet mst, minthogy megprblja szpen
befejezni a program mkdst.
E.7. Tancsok
[1] Legynk tisztban azzal, milyen szint kivtelbiztossgra van szksgnk. E.2.
[2] A kivtelbiztossgnak egy teljes kr hibatrsi stratgia rsznek kell lennie.
E.2.
[3] Az alapbiztostst minden osztlyhoz rdemes megvalstani, azaz az invarin-
sokat mindig tartsuk meg s az erforrs-lyukakat mindig kerljk el. E.2,
E.3.2, E.4.
[4] Ahol lehetsg s szksg van r, valstsunk meg ers biztostst, azaz egy
mvelet vagy sikeresen hajtdjon vgre, vagy minden operandust hagyja vlto-
zatlanul. E.2, E.3.
[5] Destruktorokban ne fordulhasson el 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 mveletek alapos vizsglatt. E.3.
[8] A sablon osztlyokat gy tervezzk meg, hogy azok tltszak legyenek a ki-
vtelek szmra. E.3.1.
[9] Az init() fggvny helyett hasznljunk konstruktort az erforrsok lefoglals-
hoz. E.3.5.
[10] Adjunk meg invarinst minden osztlyhoz, hogy ezzel pontosan meghatrozzuk
rvnyes llapotaikat. E.2, E.6.
[11] Gyzdjnk meg rla, hogy objektumaink mindig rvnyes llapotba llthatk
anlkl, hogy kivtelektl kellene tartanunk. E.3.2, E.6.
[12] Az invarinsok mindig legyenek egyszerek. E.3.5.
[13] Kivtel kivltsa eltt minden objektumot lltsunk rvnyes llapotba. E.2,
E.6.
[14] Kerljk el az erforrs-lyukakat. E.2, E.3.1, E.6.
[15] Az erforrsokat kzvetlenl brzoljuk. E.3.2, E.6.
[16] Gondoljunk r, hogy a swap() fggvny gyakran hasznlhat az elemek mso-
lsa helyett. E.3.3.
E. Kivtelbiztossg a standard knyvtrban 1303
[17] Ha lehetsg van r, a try blokkok hasznlata helyett a mveletek sorrendjnek
j megvlasztsval kezeljk a problmkat. E.3.4.
[18] Ne trljk a rgi informcikat addig, amg a helyettest adatok nem vlnak
biztonsgosan elrhetv. E.3.3, E.6.
[19] Hasznljuk a kezdeti rtkads az erforrs megszerzsvel mdszert. E.3,
E.3.2, E.6.
[20] Vizsgljuk meg, hogy asszociatv trolinkban az sszehasonlt mveletek m-
solhatk-e. E.3.3.
[21] Keressk meg a ltfontossg adatszerkezeteket s ezekhez adjunk meg olyan
mveleteket, melyek ers biztostst adnak. E.6.
E.8. Gyakorlatok
1. (*1) Soroljuk fel az sszes kivtelt, amely elfordulhat az E.1 pont f()
fggvnyben.
2. (*1) Vlaszoljunk az E.1 pontban, a plda utn szerepl krdsekre.
3. (*1) Ksztsnk egy Tester osztlyt, amely idnknt a legalapvetbb mveletek-
ben okoz kivtelt, pldul a msol konstruktorban. A Tester osztly segtsg-
vel prbljuk ki sajt standard knyvtrunk trolit.
4. (*1) Keressk meg a hibt az E.3.1 pontban szerepl vector konstruktornak
rendezetlen vltozatban s rjunk programot, amely tnkreteszi az osztlyt.
Ajnls: elszr rjuk meg a vector destruktort.
5. (*2) Ksztsnk egyszer listt, amely alapbiztostst nyjt. llaptsuk meg na-
gyon pontosan, milyen kvetelmnyeket kell a felhasznlnak teljestenie a biz-
tosts megvalstshoz.
6. (*3) Ksztsnk egyszer listt, amely ers biztostst nyjt. Alaposan ellenriz-
zk az osztly mkdst. Indokoljuk meg, mirt tartjuk ezt a megoldst bizton-
sgosabbnak.
7. (*2.5)rjuk jra a 11.12 String osztlyt gy, hogy ugyanolyan biztonsgos le-
gyen, mint a szabvnyos trolk.
8. (*2) Hasonltsuk ssze a vector osztlyban meghatrozott rtkads s
a safe_assign() fggvny klnbz vltozatait a futsi id 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).
Fggelkek s trgymutat 1304
10. (*2) rjunk a vector osztlyhoz alapbiztostssal egy egyelem s egy tbbelem
erase(), illetve insert() fggvnyt.E.3.2.
11. (*2) rjunk a vector osztlyhoz ers biztostssal egy egyelem s egy tbbelem
erase(), illetve insert() fggvnyt (E.3.2). Hasonltsuk ssze ezen fggvnyek
kltsgt s bonyolultsgt az elz feladatban szerepl fggvnyekvel.
12. (*2) Ksztsnk egy safe_insert() fggvnyt (E.4.2), amely egy ltez vector ob-
jektumba szr be elemet (nem pedig egy ideiglenes vltozt msol le). Milyen
kiktseket kell tennnk a mveletekre?
13. (*2.5) Hasonltsuk ssze mret, bonyolultsg s hatkonysg szempontjbl
a 12. s a 13. feladatban szerepl safe_insert() fggvnyt az E.4.2 pontban be-
mutatott safe_insert() fggvnnyel.
14. (*2.5) rjunk egy jobb (gyorsabb s egyszerbb) safe_insert() fggvnyt, kifeje-
zetten 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 megfelelen 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 szab-
vnyhoz. Nzzk t dokumentcijt s llaptsuk meg, milyen kivtelbiztossgi
lehetsgek llnak rendelkezsnkre. Vgezznk nhny tesztet, hogy meglla-
ptsuk, mennyire rugalmas a trol a memriafoglalsbl vagy a felhasznl ltal
megadott programrszekbl szrmaz kivtelekkel szemben. Hasonltsuk ssze
a tapasztaltakat a standard knyvtr megfelel troljnak szolgltatsaival.
17. (*3) Prbljuk optimalizlni az E.3 pontban szerepl vector osztlyt a kivtelek
lehetsgnek figyelmen kvl hagysval. Pldul trljnk minden try blok-
kot. 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 megenged-
jk, 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 tbbelem insert() utasts-
ban s a resize() fggvnyben?
20. (*3) rjuk meg a hash_map (17.6) olyan vltozatt, amely ugyanolyan biztons-
gos, mint a szabvnyos trolk.
E. Kivtelbiztossg a standard knyvtrban 1305