home *** CD-ROM | disk | FTP | other *** search
/ Chip 2000 July / Chip_2000-07_cd.bin / obsahy / Chip_txt / TXT / 172-175.TXT < prev    next >
Text File  |  2000-06-06  |  16KB  |  185 lines

  1. Jazyk C++
  2. Novß pam∞¥ podruhΘ
  3. V kv∞tnovΘm Φφsle Chipu jsme se p°i povφdßnφ o operßtorech new a delete seznßmili p°edevÜφm s pozadφm jejich fungovßnφ a s n∞kter²mi novinkami, kterΘ v tomto ohledu p°inesl standard ISO/ANSI jazyka C++. Dnes se podφvßme p°edevÜφm na problΘmy, na kterΘ m∙₧e programßtor p°i jejich pou₧itφ narazit.
  4.  
  5. Jako v₧dy i p°i pou₧φvßnφ operßtor∙ new a delete m∙₧eme ud∞lat chyby a "zad∞lat" si tak na sluÜnou porci problΘm∙. Podφvejme se te∩ na n∞kterΘ obzvlßÜt∞ p∞knΘ. Nßsledujφcφ p°φklady pochßzejφ nejen z program∙ zaΦφnajφcφch cΘΦka°∙, ale bohu₧el i z knih û naÜich i zahraniΦnφch. N∞kterΘ z nich dokonce nesly oznaΦenφ "uΦebnice"...
  6.  
  7. Kontrola v²sledku
  8. Operßtor new nemusφ usp∞t. Pam∞¥ poΦφtaΦe m∙₧e b²t sice velkß, ale je v₧dy koneΦnß. Proto je t°eba v²sledek operßtoru new kontrolovat. To znamenß podle okolnostφ bu∩ testovat, zda je v²sledek (vrßcenß adresa) r∙zn² od 0, nebo uzav°φt alokaΦnφ v²raz do bloku try.
  9. Nedßvno jsem v jednΘ zahraniΦnφ knize naÜel tvrzenφ, ₧e testovat v²sledek operßtoru new vlastn∞ nenφ nutnΘ û dφky mechanismu virtußlnφ pam∞ti pr² dnes majφ programy k dispozici tolik pam∞¥ovΘho prostoru, ₧e ho prakticky nelze vyΦerpat. Nemohu se ubrßnit dojmu, ₧e se tφm °ada programßtor∙ opravdu °φdφ. UvedenΘ tvrzenφ vypadß v∞rohodn∞, nebo¥ 4 GB jsou opravdu hodn∞, nebo alespo≥ nßm to tak p°ipadß. Nikde vÜak nenφ psßno, ₧e nßÜ program pob∞₧φ v₧dy v prost°edφ s dostateΦn∞ velk²m diskov²m prostorem nebo ₧e zßrove≥ s nφm nepob∞₧φ dalÜφ programy konzumujφcφ obrovskΘ mno₧stvφ pam∞ti. Tak₧e zmφn∞nΘ tvrzenφ p°ece jen p°φliÜ rozumnΘ nenφ.
  10. Ostatn∞ v²roky tohoto typu zastarßvajφ velice rychle. Vzpome≥me jen, jak Bill Gates roku 1981 prohlaÜoval, ₧e 640 KB operaΦnφ pam∞ti by m∞lo b²t dost pro ka₧dΘho...
  11.  
  12. P°edefinovßnφ globßlnφch operßtor∙
  13. Na samotnΘm p°edefinovßnφ globßlnφch operßtor∙ new a delete ve skuteΦnosti nenφ nic ÜpatnΘho. Musφme ale mφt stßle na pam∞ti, ₧e nßhrada standardnφch funkcφ operator new(size_t) a dalÜφch platφ po celou dobu b∞hu programu, ₧e zaΦφnß jeÜt∞ p°ed spuÜt∞nφm funkce main() a trvß i po jejφm ukonΦenφ. To znamenß, ₧e se uplatnφ i p°i vytvß°enφ globßlnφch instancφ knihovnφch t°φd (nap°. proud∙ cin, cout atd.) a p°i jejich uvol≥ovßnφ. 
  14. Je tedy t°eba takovou nßhradu peΦliv∞ uvß₧it, nebo¥ m∙₧e mφt nep°φjemnΘ nßsledky. Nap°φklad pokusy s alokacφ pam∞ti do "arΘny", vyhrazenΘho pole, mohou zp∙sobit zhroucenφ programu, nebo¥ se nemusφ poda°it alokovat dostateΦnΘ mno₧stvφ pam∞ti pro objektovΘ datovΘ proudy. 
  15. Existujφ ovÜem i subtiln∞jÜφ chyby, kterΘ m∙₧e p°edefinovßnφ globßlnφch operßtor∙ new a delete zp∙sobit. Podφvejme se na p°φklad. Chceme û nap°φklad kv∙li lad∞nφ û zajistit, aby operßtor new inicializoval p°id∞lenou pam∞¥ urΦitou hodnotou,. aby nap°φklad ulo₧il do vÜech bit∙ hodnotu 1. NapφÜeme tedy nßsledujφcφ funkci:
  16. #include <stdlib.h>
  17. #include <memory.h>
  18. #include <new>
  19. void* operator new(size_t s) throw(std::bad_alloc)
  20. {
  21. void *p = malloc(s);
  22. if(!p) throw std::bad_alloc();
  23. memset(p,0xff,s);
  24. return p;
  25. }
  26. Bude to v po°ßdku? TΘm∞°. Tato funkce se chovß podobn∞ jako standardnφ operßtor new, a₧ na to, ₧e nespolupracuje s funkcφ set_new_handler(). Pokud by na to n∞kterß Φßst programu spolΘhala, vzniknou chyby, kterΘ se t∞₧ko hledajφ.
  27. Ke svΘrßzn²m problΘm∙m m∙₧e vΘst pou₧itφ n∞kter²ch standardnφch objekt∙ v p°edefinovan²ch funkcφch operator new() nebo operator delete(). Kdybychom nap°φklad vytvo°ili funkci operator delete(), kterß bude krom∞ uvol≥ovßnφ pam∞ti informovat o tom, ₧e je volßna, dejme tomu takto:
  28. void operator delete(void*p)
  29. {
  30.     std::cout << "volß se operßtor delete" << std::endl;
  31.     free(p);
  32. }
  33. doΦkali bychom se nejspφÜ nep°φjemnΘho p°ekvapenφ. V n∞kter²ch p°ekladaΦφch by program po ukonΦenφ ohlßsil nedefinovanou chybu, v n∞kter²ch by vznikl p°i pou₧itφ operßtoru delete nekoneΦn² cyklus. ProΦ?
  34. Standardnφ proudy si mohou p°i pou₧itφ alokovat pomocnou pam∞¥ a k tomu vyu₧φvajφ operßtory new a delete. To ale znamenß, ₧e po vstupu do funkce operator delete() se pou₧ije operßtor new, v zßp∞tφ pak operßtor delete, kter² zavolß funkci operator delete(), ta pou₧ije op∞t new a delete atd. Program pak skonΦφ vyΦerpßnφm zßsobnφku.
  35. PodobnΘ problΘmy se mohou objevit takΘ p°i pou₧itφ objektov²ch datov²ch proud∙ ve funkci operator new(), kterß nahrazuje standardnφ verzi.
  36. To znamenß, ₧e p°edefinovßnφ standardnφch operßtor∙ se û pokud to jde û vyhneme. Nic nßm toti₧ nebrßnφ funkci operator new()p°et∞₧ovat, tj. definovat vlastnφ verze s dodateΦn²mi parametry. Tyto p°etφ₧enΘ verze pou₧ijeme jen tam, kde je opravdu pot°ebujeme, a pro standardnφ objekty ponechßme standardnφ new. 
  37.  
  38. Dvojφ volßnφ konstruktoru
  39. Nßsledujφcφ chyba m∙₧e vypadat neuv∞°iteln∞, naÜel jsem ji vÜak v jednΘ n∞meckΘ knize, kterß se tvß°ila jako referenΦnφ p°φruΦka jazyka C++. Autor p°edvßd∞l operßtor new definovan² jako metodu takto:
  40. class {
  41.     public:
  42.     X();
  43.     void* operator new(size_t s);
  44.     };
  45. void* X::operator new(size_t s)
  46. {
  47.     X* x = ::new X;
  48.     // N∞jakß ·prava vytvo°enΘ instance
  49.     return x;
  50. }
  51. Zde autor v operßtoru new nejprve vytvo°φ pomocφ globßlnφho operßtoru novou instanci, n∞jak ji upravφ a ukazatel na ni vrßtφ. Vypadß to docela dob°e, ale je tu nejmΘn∞ jeden problΘm: Pro tuto instanci se bude dvakrßt volat konstruktor, a to m∙₧e mφt podobn∞ zhoubnΘ nßsledky, jako kdy₧ se konstruktor v∙bec nezavolß. Jestli₧e toti₧ n∞kde v programu napφÜeme nap°.
  52. X* ux = new X;
  53. prob∞hnou obvyklΘ operace û nejprve se zavolß metoda X::operator new(), kterß by m∞la vyhradit pam∞¥. Ta ji opravdu vyhradφ, ovÜem pou₧ije k tomu globßlnφ operßtor new, a ten pro tuto pam∞¥ ihned zavolß konstruktor t°φdy X. Pak X::operator new()ukazatel na vytvo°enou instanci vrßtφ. Po nßvratu pro ni zavolß operßtor new znovu konstruktor. Kdyby konstruktor t°φdy X nap°φklad alokoval dynamickou pam∞¥, otevφral soubory apod., mohou nastat problΘmy.
  54. Pokud by programßtor cht∞l podobn²m zp∙sobem postupovat, m∞l by v metod∞ X::operator new() pou₧φt zßpis operßtorovΘ funkce:
  55. void* X::operator new(size_t s)
  56. {
  57.     X* x = ::operator new(s);
  58.     // N∞jakß ·prava alokovanΘ pam∞ti
  59.     return x;
  60. }
  61. Takto definovan² operßtor new vÜak vlastn∞ nahrazuje konstruktor, a to je zbyteΦnΘ. Pokud nßm tedy nejde o n∞jakou "preventivnφ" inicializaci, kterß mß t°eba usnadnit hledßnφ chyb, je lepÜφ ponechat inicializaci konstruktoru û to je p°ece jeho vlastnφ ·loha.
  62.  
  63. Zd∞d∞nΘ delete
  64. Deklarujeme-li funkce operator new() a operator delete() jako metody, budou statickΘ, i kdy₧ klφΦovΘ slovo static neuvedeme. To znamenß, ₧e nemohou b²t virtußlnφ û a to m∙₧e obΦas vΘst k problΘm∙m. Podφvejme se na p°φklad:
  65. int a[1000];
  66. class X
  67. {
  68. public:
  69.     void *operator new(size_t s){
  70.         cout << "new X" << endl;
  71.         return a;
  72.     }
  73.     void operator delete(void* p) {
  74.         cout << "delete X" << endl;
  75.     }
  76. };
  77. class Y: public X
  78. {
  79. public:
  80.     void *operator new(size_t s){
  81.         cout << "new Y" << endl;
  82.         return a;
  83.     }
  84.     void operator delete(void* p){
  85.         cout << "delete Y" << endl;
  86.     }
  87. };
  88. Zde jsme deklarovali t°φdu Y jako potomka t°φdy X. Jak p°edek, tak potomek obsahujφ vlastnφ verze operßtor∙ new a delete. (Jejich implementace zde mß p°edevÜφm za ·kol vypsat upozorn∞nφ û na n∞m bude toti₧ nejsnßze vid∞t, oΦ jde.)
  89. P°i konstrukci novΘ instance v∞tÜinou problΘmy nenastanou. NapφÜeme-li v programu
  90. X* ux = new Y;
  91. zavolß se metoda Y::operator new(), jak oΦekßvßme, a vypφÜe °et∞zec new Y. Jestli₧e ale napφÜeme
  92. delete ux;
  93. zavolß se metoda p°edka, X::operator delete(), kterß vypφÜe delete X û a to je Üpatn∞ (jinak bychom nemuseli definovat v potomkovi novou verzi tΘto funkce). 
  94. ╪eÜenφ je ovÜem jednoduchΘ: StaΦφ v p°edkovi, ve t°φd∞ X, definovat virtußlnφ destruktor. P°idßme-li tedy do deklarace t°φdy X °ßdek
  95. virtual ~X(){}
  96. bude vÜe v po°ßdku; p°φkazem
  97. delete ux;
  98. zavolßme toti₧ opravdu operßtor delete pro t°φdu Y.
  99.  
  100. Alokace vφcerozm∞rnΘho pole
  101. O tΘto chyb∞ jsem v Chipu u₧ kdysi psal. V zaΦßteΦnick²ch programech se vÜak objevuje s ·pornou pravidelnostφ, a proto proklßdßm za ·ΦelnΘ se k nφ vrßtit. 
  102. Podφvejme se na nßsledujφcφ p°φklad:
  103. int** m = (int**)new int[2][3];    // !!!
  104. ProblΘm je, ₧e pokud n∞co takovΘho napφÜete, v n∞kter²ch prost°edφch û nap°. ve stßle jeÜt∞ ₧ijφcφm operaΦnφm systΘmu DOS û m∙₧e vßÜ program dlouhou dobu b∞₧et, ani₧ by se cokoli ÜpatnΘho d∞lo. Pak se ovÜem zhroutφ, nebo¥ si p°epφÜe Φßst pam∞ti û data, k≤d programu, Φßst operaΦnφho systΘmu, podle toho, co m∙₧e napßchat v∞tÜφ Ükody.
  105. Dokonce i v prost°edφch s ochranou pam∞ti û nap°φklad pod Win32 û m∙₧e tato konstrukce za jist²ch okolnostφ chvφli fungovat, pak ovÜem skonΦφ v²jimkou, poruÜenφm ochrany pam∞ti.
  106. Jak to tedy mß vypadat? Pokud chceme alokovat pole, musφme pou₧φt ukazatel na prvnφ prvek. Dvourozm∞rnΘ pole se sklßdß z jednorozm∞rn²ch polφ, tak₧e pot°ebujeme ukazatel na pole, nikoli ukazatel na ukazatel. P°esn∞ji, pole vytvo°enΘ v²razem new int[2][3] je pole o dvou prvcφch slo₧enΘ z polφ o t°ech prvcφch typu int. Pot°ebujeme ukazatel na jeho prvnφ prvek, tedy ukazatel na pole o t°ech prvcφch typu int:
  107. int (*mat)[3] = new int[2][3];    // OK
  108. S takto alokovan²m polem lze zachßzet jako s "normßlnφm" polem, m∙₧eme nap°. napsat
  109. for(int i = 0; i < 2; i++)
  110.     for(int j = 0; j < 3; j++)
  111.         mat[i][j] = 10*i+j;
  112. Zmφn∞nß chyba nesporn∞ pochßzφ z oblφbenΘho tvrzenφ mnoha autor∙ uΦebnic jazyk∙ C a C++, ₧e pole a ukazatele jsou v t∞chto jazycφch jedno a totΘ₧. (Nevφm, jak m∙₧e n∞kdo n∞co takovΘho v∙bec napsat, nicmΘn∞ nejde o nijak vzßcnΘ tvrzenφ.) Odtud je ji₧ jen krok k p°edstav∞, ₧e tedy dvourozm∞rnΘ pole je totΘ₧ co ukazatel na ukazatel. Navφc p°ekladaΦ tuto chybu nezachytφ, nebo¥ ukazatel na ukazatel opravdu lze dvakrßt indexovat û v²znam je ovÜem pon∞kud jin² ne₧ dvakrßt indexovan² identifikßtor pole nebo ukazatel na pole. 
  113. Je-li M ukazatel na ukazatel na int, oΦekßvß p°ekladaΦ, ₧e jde o ukazatel na prvnφ prvek pole typu int a dovolφ nßm ho indexovat. Podobn∞ je-li m ukazatel na ukazatel na int, oΦekßvß p°ekladaΦ, ₧e jde o prvnφ prvek pole slo₧enΘho z ukazatel∙ na int. Pak m[i] bude znamenat i-t² prvek tohoto pole, tedy ukazatel na int, a tedy ukazatel na prvnφ prvek pole typu int. Nakonec m[i][j] je prvek v poli, na kterΘ tento ukazatel ukazuje. Nßzorn∞ji je to vid∞t na obrßzku 1.
  114. Na druhΘ stran∞ je-li mat ukazatel na jednorozm∞rnΘ pole, oΦekßvß p°ekladaΦ, ₧e jde o prvnφ prvek pole slo₧enΘho z polφ, mat[i] je i-t² prvek tohoto pole a mat[i][j] je j-t² prvek i-tΘho prvku (obr. 2).
  115. Podrobn∞jÜφ rozbor najdete v Φlßnku Kdy₧ se cΘΦka°i s plusy neda°φ (4) v Chipu 11/95 nebo v mΘ knize Pasti a propasti jazyka C++ (Grada 1997, ISBN 80-7169-607-2).
  116. Ve skuteΦnosti zde narß₧φme jeÜt∞ na jeden problΘm: ProΦ je v zßpisu oznaΦenΘm t°emi vyk°iΦnφky p°etypovßnφ? Proto₧e p°ekladaΦ odmφtl tento p°φkaz p°elo₧it s od∙vodn∞nφm, ₧e nedokß₧e konvertovat ukazatel na pole na ukazatel na ukazatel. U₧ to m∞lo programßtora varovat, ₧e je n∞co v nepo°ßdku û operßtor new vracφ v₧dy ukazatel na typ, jak² si autor poruΦil. Zde ovÜem programßtor ignoroval upozorn∞nφ a prosadil svou, ani₧ o v∞ci p°em²Ülel.
  117.  
  118. Pole objekt∙
  119. Podφvejme se na nßsledujφcφ deklaraci t°φdy Z:
  120. class Z
  121. {
  122. public:
  123.     void* operator new(size_t s);
  124.     Z();
  125.     // ... a dalÜφ slo₧ky
  126. };
  127. Tato t°φda obsahuje operßtor new pro alokaci jednoduch²ch prom∞nn²ch, nikoli pro alokaci pole. To znamenß, ₧e napφÜeme-li
  128. Z* uz = new Z;
  129. Z* upz = new Z[10];
  130. pou₧ije se v prvnφm p°φpad∞ pro alokaci pam∞ti metoda Z::operator new(), avÜak ve druhΘm p°φpad∞ se pou₧ije globßlnφ funkce operator new[](). Pokud chceme °φdit takΘ alokaci polφ t°φdy Z, musφme doplnit odpovφdajφcφ metodu. Obvykle staΦφ, kdy₧ se "polnφ" alokaΦnφ funkce odvolß na "obyΦejnou":
  131. void* Z::operator new[](unsigned s)
  132. {
  133.     return operator new(s);
  134. }
  135. Poznamenejme, ₧e takto je zpravidla implementovßna i standardnφ globßlnφ funkce operator new[]().
  136. P°i implementaci "obyΦejnΘ" alokaΦnφ funkce, tj. metody operator new(size_t s), musφme poΦφtat s tφm, ₧e bude volßna i s hodnotou parametru s, kterß nenφ rovna velikosti instance t°φdy Z. V p°φpad∞ alokace pole o N prvcφch m∙₧e mφt parametr s obecn∞ hodnotu N*sizeof(Z)+k, kde k p°edstavuje jakousi re₧ii (t°eba mφsto, do kterΘho si program ulo₧φ poΦet prvk∙ pole pro pozd∞jÜφ orientaci, nap°φklad p°i volßnφ destruktor∙).
  137.  
  138. New mß mφt svΘ delete
  139. Podφvejme se znovu na t°φdu Z z p°edchozφho odstavce. Jestli₧e alokujeme instanci p°φkazem
  140. Z* uz = new Z;
  141.  a pak ji uvolnφme p°φkazem
  142. delete uz;
  143. pou₧ije se k alokaci metoda Z::operator new(), avÜak k uvoln∞nφ globßlnφ funkce operator delete(). To je nejspφÜ chyba: Pokud operßtor new pou₧φvß p°i alokaci n∞jak² zvlßÜtnφ postup, nap°φklad p°id∞luje pam∞¥ ve zvlßÜtnφ hald∞, je nezbytnΘ pam∞¥ stejn²m zp∙sobem i uvol≥ovat, tedy definovat takΘ metodu operator delete(). (TotΘ₧ platφ i pro "polnφ" verze t∞chto operßtor∙.)
  144.  
  145. JeÜt∞ jednou pole objekt∙
  146. ObΦas takΘ zapomeneme, ₧e p°i uvol≥ovßnφ pole je t°eba pou₧φt operßtor delete[], nikoli jen delete. Pokud pracujeme s neobjektov²mi poli, v∞tÜinou to projde. V p°φpad∞ polφ objektov²ch typ∙ je situace horÜφ, liÜφ se vÜak p°ekladaΦ od p°ekladaΦe. Je-li X t°φda a napφÜeme-li
  147. X* ux = new X[N];
  148. delete ux; // Mß b²t delete[] ux;
  149. obvykle se nezavolß sprßvn² destruktor pro vÜechny instance. M∙₧e vÜak dojφt i k poruÜenφ ochrany pam∞ti.
  150.  
  151. Zßpis typu
  152. Operßtor new mß ni₧Üφ prioritu ne₧ nap°φklad operßtor volßnφ funkce. Proto m∙₧e p°ekladaΦ odmφtnout n∞kterß  komplikovan∞jÜφ oznaΦenφ typu za klφΦov²m slovem new. Jestli₧e chceme alokovat dynamickou prom∞nnou typu "ukazatel na funkci typu void bez parametr∙" a napφÜeme
  153. void (** v)() = new void (*)();
  154. ohlßsφ p°ekladaΦ nejspφÜ °adu podivn²ch chyb.
  155. Tato situace mß n∞kolik °eÜenφ. StaΦφ t°eba oznaΦenφ typu uzßvorkovat:
  156. void f(void);
  157. void (** v)(void) = new (void (*)())(f);
  158. (**v)();        // Volßnφ funkce f()
  159. Zde jsme nov∞ vytvo°enΘ prom∞nnΘ p°i°adili jako poΦßteΦnφ hodnotu adresu funkce f() a  vzßp∞tφ jsme tuto funkci zavolali.
  160. Asi nejp°ehledn∞jÜφ je pojmenovat po₧adovan² typ pomocφ deklarace typedef, nap°φklad
  161. typedef void (*funkce)(void);
  162. a pak nov∞ zavedenΘ pou₧φt v alokaΦnφm v²razu:
  163. funkce* u = new funkce(f);
  164.  
  165. T°φda je obor viditelnosti
  166. Nßsledujφcφ p°φklad skonΦφ chybou p°i p°ekladu, mΘn∞ zkuÜenφ programßto°i pak ovÜem obvi≥ujφ p°ekladaΦ, ₧e obsahuje chybu (to jsem si kdysi myslel i jß).
  167. Class X
  168. {
  169.     public:
  170.     void* operator new(size_t s, int a);
  171.     // ... a dalÜφ slo₧ky
  172. };
  173.  
  174. X* ux = new X;    // Chyba
  175. T°φda X obsahuje operßtor new deklarovan² jako metodu s jednφm dodateΦn²m parametrem, nicmΘn∞ v nßsledujφcφm p°φkazu pou₧φvßme operßtor new bez dodateΦn²ch parametr∙. I kdy₧ se zdß, ₧e by p°ekladaΦ m∞l podle poΦtu a typu parametr∙ zjistit, ₧e chceme pou₧φt globßlnφ operßtor new, nepoznß to a ohlßsφ, ₧e ve t°φd∞ X operßtor new s po₧adovan²mi parametry neexistuje. D∙vod je z°ejm²: t°φda je toti₧ takΘ "oblast viditelnosti" a v nφ je globßlnφ operßtor new zastφn∞n lokßlnφ definicφ. Pokud chceme pou₧φt globßlnφ operßtor new, musφme si o n∞j explicitn∞ °φci pomocφ rozliÜovacφho operßtoru ::, pak bude vÜe v po°ßdku:
  176. X* ux = ::new X;    // OK
  177.  
  178. Konstruktory, destruktory a skalßrnφ typy
  179. V obou dφlech povφdßnφ o operßtorech new a delete jsme stßle hovo°ili o konstruktorech a destruktorech, jako kdybychom nealokovali nic jinΘho ne₧ instance objektov²ch typ∙. Ve skuteΦnosti lze vÜe, co jsme °ekli, p°enΘst i na skalßrnφ datovΘ typy. Standardnφ C++ toti₧ dovoluje i pro tyto typy pou₧φvat zßpisy jako int() nebo a.~int(), kde a je prom∞nnß typu int ("konstruktor" nebo "destruktor" typu int). Tento "konstruktor" inicializuje zpravidla hodnotou 0, "destruktor" skalßrnφho typu ned∞lß nic. Proto m∙₧eme takΘ s klidem hovo°it o inicializaci dynamicky alokovanΘ skalßrnφ prom∞nnΘ pomocφ konstruktoru.
  180. I kdy₧ to vypadß podivn∞, mß uvedenΘ pravidlo dobr² d∙vod: Umo₧≥uje pou₧φvat naprosto stejn²m zp∙sobem objektovΘ typy a skalßrnφ typy v Üablonßch a v n∞kter²ch dalÜφch situacφch.
  181.  
  182. JeÜt∞ nenφ konec...
  183. Operßtory new a delete nejsou jedinΘ nßstroje pro alokaci pam∞ti v C++. Vedle funkcφ malloc(), calloc()a free(), zd∞d∞n²ch po jazyku C, p°inesl standard jazyka i tzv. alokßtory. To jsou t°φdy, kterΘ zapouzd°ujφ nßstroje pro alokaci pam∞ti a kterΘ se hojn∞ vyu₧φvajφ p°edevÜφm ve standardnφ ÜablonovΘ knihovn∞ C++. O nich si povφme n∞kdy jindy v samostatnΘm Φlßnku.
  184. Miroslav Virius
  185.