Professional Documents
Culture Documents
PRZYKADOWY ROZDZIA
SPIS TRECI
KATALOG KSIEK
KATALOG ONLINE
ZAMW DRUKOWANY KATALOG
TWJ KOSZYK
DODAJ DO KOSZYKA
CENNIK I INFORMACJE
ZAMW INFORMACJE
O NOWOCIACH
ZAMW CENNIK
CZYTELNIA
FRAGMENTY KSIEK ONLINE
Wydawnictwo Helion
ul. Chopina 6
44-100 Gliwice
tel. (32)230-98-63
e-mail: helion@helion.pl
Spis treci
Przedmowa ....................................................................................... 7
Rozdzia 1. Programowanie uoglnione i biblioteka standardowa jzyka C++ ...... 13
Zagadnienie 1. Poprawne i niepoprawne uywanie klasy vector .................................. 14
Zagadnienie 2. Folwark metod formatowania. Cz 1. sprintf .................................... 21
Zagadnienie 3. Folwark metod formatowania. Cz 2.
Standardowe (lub olniewajce) alternatywy
Zagadnienie 4. Funkcje skadowe biblioteki standardowej .......................................... 36
Zagadnienie 5. Smaczki programowania uoglnionego. Cz 1. Podstawy (sic!) ...... 40
Zagadnienie 6. Smaczki programowania uoglnionego. Cz 2.
Wystarczajco oglne? ........................................................................ 43
Zagadnienie 7. Dlaczego nie naley specjalizowa szablonw funkcji? ...................... 49
Zagadnienie 8. Zaprzyjanianie szablonw .................................................................. 55
Zagadnienie 9. Ograniczenia sowa kluczowego export. Cz 1. Podstawy ............... 64
Zagadnienie 10. Ograniczenia sowa kluczowego export. Cz 2.
Interakcje, uyteczno i wskazwki ................................................... 72
Spis treci
Rozdzia 2.
Zagadnienia i techniki
zwizane z bezpieczn
obsug wyjtkw
Obsuga wyjtkw jest podstawowym mechanizmem zgaszania bdw w jzyku C++
i innych wspczesnych jzykach programowania. W ksikach Exceptional C++1
[Sutter00] oraz More Exceptional C++2 [Sutter02] szczegowo przedstawiam wiele
zagadnie zwizanych z okreleniem, czym jest bezpieczna obsuga wyjtkw i jak
pisa kod z bezpieczn obsug wyjtkw. Opisuj take waciwoci jzyka i interakcje,
o ktrych musisz pamita.
W tym rozdziale kontynuuj te rozwaania, skupiajc si na pewnych waciwociach
jzyka specyficznych dla obsugi wyjtkw. Na pocztku odpowiadam na odwieczne
pytanie czy bezpieczna obsuga wyjtkw to tylko wpisywanie try i catch w odpowiednich miejscach? Jeli nie, to co jeszcze? Nad czym musisz si zastanowi, tworzc
w programie schemat obsugi wyjtkw?
Odchodzc nieco od tematu warto powici cae zagadnienie, aby przedstawi
powody, dla ktrych pisanie kodu z bezpieczn obsug wyjtkw to czysta korzy.
Takie postpowanie wie si ze stylem programowania, ktry prowadzi do bardziej
stabilnego i atwiejszego w pielgnacji kodu, pomijajc nawet korzyci wynikajce ze
stosowania wyjtkw. Jest jednak pewne ograniczenie tych korzyci i mylenia na zasadzie im wicej, tym lepiej. W przypadku specyfikacji wyjtkw ograniczenie to jest
szczeglnie widoczne. Dlaczego wyjtki istniej w jzyku? Dlaczego ich wystpowanie
jest dobrze uzasadnione? I dlaczego mimo to nie powiniene uywa ich w programach?
Wydanie polskie: Wyjtkowy jzyk C++. 40 nowych amigwek, zada programistycznych i rozwiza,
Helion, 2005 przyp. tum.
84
Tego i innych rzeczy dowiesz si, czerpic z fontanny wiedzy wspczesnego wyjtkowego rodowiska programistw.
Zagadnienie 11. Bloki try i catch
Stopie trudnoci: 3
Czy bezpieczna obsuga wyjtkw to tylko wpisywanie try i catch w odpowiednich miejscach?
Jeli nie, to co jeszcze? Nad czym musisz si zastanowi, tworzc w programie schemat
obsugi wyjtkw?
Pytanie profesora
1. Do czego suy blok try?
Pytania magistra
2. Pisanie kodu z bezpieczn obsug wyjtkw polega gwnie na wpisywaniu try
i catch w odpowiednich miejscach. Przeprowad analiz tego stwierdzenia.
3. Kiedy naley stosowa bloki try i catch? Kiedy nie naley ich stosowa?
Rozwizanie
Zabawa w berka
1. Do czego suy blok try?
Blok try to fragment kodu (zoone wyraenie), ktry program prbuje wykona. Po
bloku tym znajduje si jeden lub wicej blokw catch, do ktrych program przechodzi
w sytuacji przechwycenia zgoszonego w bloku try wyjtku odpowiedniego typu. Na
przykad:
// Przykad 11.1. Przykadowy blok try
//
try {
if ( pewien_warunek )
throw string( "To jest cig znakw" );
else if ( pewien_inny_warunek )
throw 42;
}
catch ( const string& ) {
// Zrb co, jeli przechwycony zosta cig znakw
}
catch(...) {
// Zrb co, jeli przechwycony zostanie dowolny inny wyjtek
}
W przykadzie 11.1 kod w bloku try moe zgosi jako wyjtek cig znakw lub liczb
cakowit, a moe te w ogle nie zgosi wyjtku.
85
Krtko mwic, takie stwierdzenie obrazuje podstawowy bd w rozumieniu bezpieczestwa wyjtkw. Wyjtki s po prostu jednym ze sposobw zgaszania bdw i na
pewno wiesz, e pisanie kodu odpornego na bdy nie polega jedynie na sprawdzaniu
zwracanych wartoci i obsudze warunkw powodujcych te bdy.
W rzeczywistoci okazuje si, e bezpieczna obsuga wyjtkw rzadko wie si z wpisywaniem try i catch im rzadziej, tym lepiej. Powiniene te zawsze pamita, e
o bezpieczn obsug wyjtkw trzeba zadba ju na etapie projektowania kodu. Nie
jest to element, ktry mona doda na kocu, dopisujc kilka dodatkowych instrukcji
catch.
Z pisaniem kodu z bezpieczn obsug wyjtkw wi si trzy gwne zagadnienia:
1. Gdzie i kiedy naley zgasza wyjtki? Ta kwestia dotyczy umieszczania
instrukcji throw w odpowiednich miejscach. W szczeglnoci musisz rozway:
Po udzieleniu odpowiedzi na te pytania zwr uwag na to, e stosowanie idiomu alokacja zasobw jest inicjalizacj pozwala wyeliminowa wiele blokw try dziki automatyzacji porzdkowania. Jeli opakujesz dynamicznie przydzielane zasoby w zarzdzajce nimi obiekty, zwykle destruktor bdzie mg zwolni je automatycznie bez
potrzeby uywania blokw try i catch. Taka sytuacja jest oczywicie podana, nie
wspominajc, e taki kod jest zwykle atwiejszy do napisania i zrozumienia.
86
87
88
Podsumowanie
Pewien mdrzec powiedzia kiedy:
prowad, podaj ladem albo usu si z drogi!
W przypadku analizy bezpiecznej obsugi wyjtkw mona to sparafrazowa tak:
zgaszaj, przechwytuj albo usu si z drogi!
W praktyce ostatni przypadek usu si z drogi stanowi istotn cz analizy
i testw bezpieczestwa wyjtkw. Jest to podstawowy powd, dla ktrego pisanie kodu
z bezpieczn obsug wyjtkw nie polega gwnie na odpowiednim wpisywaniu try
i catch. Jego istot jest schodzenie z toru pocisku w odpowiednim momencie.
Zagadnienie 12. Bezpieczna obsuga wyjtkw czy warto? Stopie trudnoci: 7
Czy pisanie kodu z bezpieczn obsug wyjtkw jest warte wysiku? Kwestia ta nie powinna
budzi adnych wtpliwoci jednak czasem nadal si tak dzieje.
Pytania do profesora
1. Powtrka krtko zdefiniuj, jakie gwarancje, zdaniem Abrahamsa, powinna
89
Rozwizanie
Gwarancje Abrahamsa
1. Powtrka krtko zdefiniuj, jakie gwarancje, zdaniem Abrahamsa, powinna
Zawsze warto pisa kod, ktry zapewnia cho jedn z tych gwarancji. Wynika to z kilku
przyczyn:
1. Parafrazujc znane powiedzenie wyjtki si zdarzaj. Po prostu tak si
90
jedynie operacji, ktre nie zgaszaj bdw, aby unikn zmiany wewntrznego
stanu, dopki nie upewnisz si, e wszystkie operacje zakocz si powodzeniem.
Takie programowanie transakcyjne jest bardziej przejrzyste i bardziej bezpieczne
nawet wtedy, kiedy uywasz kodw bdw. Ile razy widziae ju funkcje
(oczywicie ponownie chodzi tu o cudze funkcje, nie Twoje), w ktrych jedna
ze cieek prowadzcych do szybkiego zwrcenia wyniku powoduje zmian
stanu obiektu, poniewa zmiana wystpia przed pniejsz nieudan operacj?
Stosuj zasad jedna klasa (lub funkcja), jedno zadanie. Funkcje, ktre
wykonuj wiele zada jednoczenie, takie jak Stack::Pop lub
EvaluateSalaryAndReturnName opisane w zagadnieniach 10. i 18. w ksice
91
Stopie trudnoci: 6
Pytania do magistra
1. Co si dzieje, kiedy zgaszany jest wyjtek niezgodny ze specyfikacj? Dlaczego?
Wydanie polskie: Wyjtkowy jzyk C++. 40 nowych amigwek, zada programistycznych i rozwiza,
Helion, 2005 przyp. tum.
92
int Func();
int Gunc() throw();
int Hunc() throw(A, B);
Pytania do profesora
3. Czy specyfikacja wyjtkw stanowi o typie funkcji? Wyjanij.
4. Czym s specyfikacje wyjtkw i co robi? Wyjanij szczegowo.
5. Kiedy warto doda do funkcji specyfikacj wyjtkw? Co powoduje, e decydujesz
Rozwizanie
Prace nad nowym standardem jzyka C++, C++0x s dobr okazj do analizy tego,
czego nauczylimy si na podstawie dowiadcze z obecnym standardem [C++03].
Znaczca wikszo standardowych waciwoci jzyka C++ jest przydatna i to wanie
o nich mwi si najwicej, poniewa nie ma sensu rozwodzi si nad mniej istotnymi
cechami. Te sabsze i mniej uyteczne waciwoci s przewanie ignorowane i zanikaj z braku uytkownikw, a wiele osb zapomni nawet o ich istnieniu (nie zawsze jest
to ze). Dlatego moesz znale stosunkowo mao artykuw na temat mniej przydatnych waciwoci, takich jak valarray, bitset, ustawienia lokalne czy dozwolone wyraenie 5[a] (chocia to ostatnie pojawia si w pewnej odmianie w jednym z kolejnych
zagadnie). To samo dotyczy, o czym si przekonasz, specyfikacji wyjtkw.
Przyjrzyjmy si teraz bliej dotychczasowym dowiadczeniom ze specyfikacj wyjtkw w jzyku C++.
Naruszanie specyfikacji
1. Co si dzieje, kiedy zgaszany jest wyjtek niezgodny ze specyfikacj? Dlaczego?
Jeli zostanie zgoszony wyjtek spoza tej listy, zostanie wywoana funkcja unexpected.
Poniej przedstawiony jest prosty przykad:
// Przykad 13.1
//
int f() throw( A, B ) {
throw C();
}
// A i B nie s zwizane z C
// Powoduje wywoanie funkcji unexpected
93
Pozostaje jednak pytanie, co powinna robi funkcja do obsugi nieoczekiwanego wyjtku? Na pewno nie moe zwraca sterowania za pomoc zwykej instrukcji return.
Moliwe s za to dwie opcje:
Funkcja ta moe przeksztaci wyjtek na inny, dopuszczony przez specyfikacj
Dotychczasowe dowiadczenia
atwo zrozumie przyczyny istnienia specyfikacji wyjtkw. W programie w jzyku
C++, jeli nie jest powiedziane inaczej, dowolna funkcja moe zgosi wyjtek dowolnego typu. Przyjrzyj si funkcji, ktr nazwaem Func (poniewa nazwa f jest straszliwie naduywana).
2. Jakie wyjtki moe zgasza kada z poniszych funkcji?
// Przykad 13.2(a)
//
int Func();
// Moe zgosi dowolny wyjtek
Domylnie funkcja Func moe zgosi dowolny wyjtek, jak jest to napisane w komentarzu. Czsto wiadomo, jakie wyjtki moe zgasza dana funkcja. Wtedy oczywicie
chcemy przekaza kompilatorowi i innym programistom informacje, ktre pozwol
ograniczy typy wyjtkw wydostajce si z funkcji. Na przykad:
// Przykad 13.2(b)
//
int Gunc() throw();
// Nie zgasza adnych wyjtkw
int Hunc() throw( A, B ); // Moe zgasza jedynie wyjtki typu A i B
W tych przypadkach specyfikacja wyjtkw funkcji pozwala okreli, jakie typy wyjtkw mog zgasza funkcje Gunc i Hunc. Komentarze w prosty sposb opisuj, co wynika z powyszych specyfikacji. Niedugo wrcimy do tego prosto, poniewa okazuje
si, e blisko rzeczywistoci jest zwodnicza.
Mona si intuicyjnie spodziewa, e opisanie wyjtkw, ktre moe zgasza dana
funkcja, jest korzystne, e im wicej informacji, tym lepiej. Jednak nie zawsze jest to
prawd, a diabe tkwi w szczegach. Chocia same zaoenia s poprawne, sposb
specyfikacji tej waciwoci w jzyku C++ powoduje, e specyfikacja wyjtkw nie
zawsze jest uyteczna i czsto okazuje si szkodliwa.
94
John Spicer, chluba Edison Design Group oraz autor duych fragmentw rozdziau dotyczcego szablonw w standardzie jzyka C++, nazwa podobno specyfikacj wyjtkw jzyka C++ systemem rozmywania typw. Jedn z najistotniejszych cech jzyka
C++ jest cisa kontrola typw i jest to bardzo korzystne. Dlaczego mielibymy nazywa specyfikacj wyjtkw systemem rozmywania typw, zamiast czci systemu
kontroli typw?
Istniej dwie proste przyczyny:
specyfikacja wyjtkw nie okrela typu funkcji,
oprcz sytuacji, w ktrych okrela.
Specyfikacja wyjtkw w definicji typu jest niedozwolona. Jzyk C++ nie pozwala na
kompilacj powyszego kodu, dlatego specyfikacja wyjtkw nie moe okrela typu
funkcji przynajmniej nie w kontekcie definicji typu. Jednak w innych przypadkach
specyfikacja wyjtkw okrela typ funkcji, na przykad wtedy, kiedy napiszesz t sam
deklaracj funkcji bez sowa kluczowego typedef:
// Przykad 13.3(b). Moesz jednak, jeli pominiesz sowo kluczowe typedef
//
void f() throw(A, B);
void (*pf)() throw(A, B);
// Poprawne
pf = f;
// Poprawne
Moesz tak przypisa wskanik do funkcji, o ile specyfikacja wyjtkw obiektu docelowego nie jest bardziej restrykcyjna ni specyfikacja obiektu rdowego:
// Przykad 13.3(c). Take koszerne, z nisk zawartoci cukru i bez tuszczu.
//
void f() throw(A,B);
void (*pf)() throw(A,B,C);
// Poprawne
pf = f;
// Poprawne, typ pf jest mniej restrykcyjny
95
Czy komentarze te s poprawne? Nie do koca. Funkcja Gunc moe zgosi wyjtek,
a funkcja Hunc moe zgosi wyjtek innego typu ni A lub B! Kompilator moe jedynie
zagwarantowa, e bezlitonie potraktuje takie funkcje, jeli zrobi co takiego przy
czym najczciej rwnie bezlitonie potraktuje take cay program.
Poniewa funkcje Gunc i Hunc mog w rzeczywistoci zgasza wyjtki, ktrych zgasza
nie powinny, kompilator nie tylko nie moe zaoy, e taka sytuacja si nie zdarzy, ale
musi take peni rol ochroniarza, ktry dba o to, aby przechwyci wszystkie niepoprawnie zgoszone wyjtki. Jeli tak si stanie, musi zosta wywoana funkcja unexpected.
Najczciej przerywa ona dziaanie programu. Dlaczego? Poniewa istniej tylko dwa
sposoby zakoczenia funkcji unexpected, z ktrych aden nie wie si z wywoaniem instrukcji return:
Moliwe jest zgoszenie innego wyjtku znajdujcego si w specyfikacji
wyjtkw. Jeli tak si stanie, wyjtek przekazywany jest tak jak w normalnej
sytuacji. Pamitaj jednak, e funkcja unexpected jest globalna w caym
96
programie istnieje tylko jedna jej wersja. Jest bardzo mao prawdopodobne,
aby taka funkcja globalna wykonywaa odpowiednie dziaania we wszystkich
przypadkach, w wyniku czego program przechodzi do funkcji terminate,
nie przechodzi przez blok catch i koczy dziaanie.
Zgosi (ten sam lub inny) wyjtek, ktrego take nie ma w specyfikacji
Poniewa naruszenie specyfikacji wyjtkw przewanie wie si z zakoczeniem dziaania programu, usprawiedliwione jest nazwanie tej sytuacji bezlitosnym potraktowaniem programu.
Wczeniej miae okazj zobaczy, jakie moliwoci wiele osb przypisuje specyfikacji
wyjtkw. Poniej znajduje si poprawiona wersja tych oczekiwa, ktra dokadniej
przedstawia rzeczywiste moliwoci [sic]6:
Gwarantuje Wymusza w czasie wykonania programu, e funkcja bdzie
Kompilator musi wygenerowa kod taki jak poniej. Szybko dziaania takiego kodu
jest zwykle porwnywalna z kodem, ktry napisaby samodzielnie (oprcz czasu spdzonego na pisaniu):
// Przykad 13.4(b). Wersja przykadu 13.4(a) rozwinita przez kompilator
//
int Hunc()
try {
return Junc();
}
catch( A ) {
throw;
}
catch( B ) {
throw;
97
}
catch( ... ) {
std::unexpected(); // Nie wywouje return! Jeli masz szczcie, zgasza wyjtek typu A
lub typu B
}
Teraz moesz atwiej zrozumie, dlaczego zamiast optymalizacji kodu opartej na zaoeniu, e zgaszane s jedynie okrelone typy wyjtkw, dzieje si co wrcz przeciwnego. Kompilator musi wykona wicej zada, aby wymusi zgaszanie jedynie okrelonych wyjtkw w czasie wykonywania programu.
98
Podsumowanie
W skrcie nie musisz si martwi o specyfikacje wyjtkw. Nawet specjalici tego
nie robi.
Poniej, w nieco mniejszym skrcie, przedstawione s najwaniejsze zagadnienia:
Specyfikacja wyjtkw moe powodowa nieoczekiwane spadki wydajnoci,
poniewa zwykle nie wiesz, jakie wyjtki mog zgasza typy, na ktrych
funkcja ta operuje.
Kiedy przedstawiaem te zagadnienia jako cz wikszego wykadu na niedawnej konferencji, zapytaem, kto z okoo 100 osb kadorazowo uywa specyfikacji wyjtkw.
Okoo poowa podniosa rce. Wtedy jaki artowni z tyu sali powiedzia (cakiem
99
susznie), e powinienem take zapyta, ile z tych osb w pewnym momencie rezygnuje ze specyfikacji wyjtkw. Zapytaem. Zgosio si mniej wicej tyle samo osb, co
poprzednio. Ta sytuacja mwi sama za siebie. Czoowi projektanci bibliotek w korporacji Boost maj podobne dowiadczenia i dlatego ich strategia dotyczca pisania specyfikacji wyjtkw sprowadza si do prostego nie rb tego [BoostES].
To prawda, e wiele osb o dobrych intencjach domagao si wczenia do jzyka specyfikacji wyjtkw i dlatego znalazy si one w standardzie. Przypomina mi to sympatyczny wierszyk, ktry pierwszy raz przeczytaem okoo 15 lat temu, kiedy pojawi
si w listach elektronicznych w czasie ferii zimowych. Sowa piewane s na melodi
Wrd nocnej ciszy, a wierszyk zatytuowany by Wrd nocnej implementacji lub
Wrd nocnego kryzysu. Opowiada on o dowiadczonym programicie, ktry lczy
po nocach w czasie ferii, aby zdy przed terminem. W tym celu dokonuje wielu cudw,
ktre pozwalaj utworzy dziaajcy system doskonale speniajcy wymagania. Niestety, na koniec zostaje na lodzie, o czym mwi cztery ostatnie linijki wierszyka:
Program gotowy, skoczone testy,
nawet poprawki klienta s w nim.
Uytkownik jednak prycha i umiecha si krzywo z cicha:
O to prosiem, lecz nie tego chc, o to prosiem, lecz nie tego chc.
To samo mona powiedzie, przygldajc si dotychczasowym dowiadczeniom ze
specyfikacj wyjtkw. Swego czasu waciwo ta przedstawiaa si obiecujco
i jest dokadnie tym, czego niektre osoby oczekiway.
Uwaaj, czego sobie yczysz, bo moe si speni.