plik


ÿþIDZ DO IDZ DO PRZYK£ADOWY ROZDZIA£ PRZYK£ADOWY ROZDZIA£ Jêzyk C++. Standardy kodowania. SPIS TRE CI SPIS TRE CI 101 zasad, wytycznych i zalecanych praktyk KATALOG KSI¥¯EK KATALOG KSI¥¯EK Autorzy: Herb Sutter, Andrei Alexandrescu KATALOG ONLINE KATALOG ONLINE T³umaczenie: Przemys³aw Szeremiota ISBN: 83-7361-849-X ZAMÓW DRUKOWANY KATALOG ZAMÓW DRUKOWANY KATALOG Tytu³ orygina³u: C++ Coding Standards: 101 Rules, Guidelines, and Best Practices Format: B5, stron: 320 TWÓJ KOSZYK TWÓJ KOSZYK Czytelny i przejrzysty kod to podstawa sprawnego tworzenia aplikacji. W przypadku DODAJ DO KOSZYKA DODAJ DO KOSZYKA pracy zespo³owej stosowanie wspólnego standardu kodowania to konieczno æ. Pisanie kodu w oparciu o okre lone standardy kodowania przyspiesza powstawanie programu, u³atwia komunikacjê pomiêdzy cz³onkami zespo³u i pozwala na szybkie wdro¿enie CENNIK I INFORMACJE CENNIK I INFORMACJE nowych programistów do projektu. Oczywi cie, w ka¿dej firmie lub zespole mo¿na ustaliæ w³asny standard kodowania  wa¿ne jest jednak, aby opiera³ siê na okre lonych ZAMÓW INFORMACJE ZAMÓW INFORMACJE regu³ach, wynikaj¹cych ze specyfiki jêzyka programowania. O NOWO CIACH O NOWO CIACH Ksi¹¿ka  Jêzyk C++. Standardy kodowania. 101 zasad, wytycznych i zalecanych ZAMÓW CENNIK praktyk zawiera opis wspomnianych regu³. Przedstawia zasady pisania kodu ZAMÓW CENNIK ród³owego i standaryzowania okre lonych zapisów, operacji i sposobów wykorzystania elementów jêzyka C++. Ka¿da z zasad jest szczegó³owo omówiona i poparta praktycznymi przyk³adami. Ksi¹¿ka prezentuje najlepsze ze znanych praktyk  zarówno CZYTELNIA CZYTELNIA  starych , jak i tych, które ca³kiem niedawno uleg³y standaryzacji, oraz opisuje techniki, FRAGMENTY KSI¥¯EK ONLINE FRAGMENTY KSI¥¯EK ONLINE o których nie s³yszeli nawet programi ci z wieloletnim do wiadczeniem. " Organizacja kodu " Styl projektowy i styl kodowania " Skalowalno æ kodu " Racjonalna i efektywna obs³uga b³êdów " Prawid³owe stosowanie elementów jêzyka " Odpowiednie korzystanie z STL " Bezpieczeñstwo typów Usprawnij pracê, stosuj¹c standardy kodowania  gdy za parê miesiêcy bêdziesz musia³ wróciæ do swoich dzisiejszych programów, przekonasz siê, ¿e by³o warto. Wydawnictwo Helion ul. Chopina 6 44-100 Gliwice tel. (32)230-98-63 e-mail: helion@helion.pl Spis tre[ci Wstp.........................................................................................................................7 RozdziaB 1. Kwestie organizacyjne ..............................................................................13 Wytyczna 0. Nie bdz maBostkowy (czyli czego nie standaryzowa).......................................... 14 Wytyczna 1. Dbaj o bezbBdn kompilacj przy najwy|szym poziomie ostrze|eD kompilatora.. 17 Wytyczna 2. Korzystaj z automatycznych systemów kompilacji ................................................ 20 Wytyczna 3. Korzystaj z systemu kontroli wersji........................................................................ 22 Wytyczna 4. Nie oszczdzaj na wzajemnej rewizji kodu............................................................. 24 RozdziaB 2. Styl projektowy ........................................................................................27 Wytyczna 5. Jednej jednostce jedno zadanie ............................................................................... 29 Wytyczna 6. Przede wszystkim poprawno[, prostota i przejrzysto[......................................... 31 Wytyczna 7. Jak i kiedy kodowa z uwzgldnieniem skalowalno[ci........................................... 33 Wytyczna 8. Wystrzegaj si przedwczesnej optymalizacji .......................................................... 36 Wytyczna 9. Wystrzegaj si przedwczesnej pesymizacji............................................................. 39 Wytyczna 10. œinimalizuj ilo[ danych globalnych i wspóBu|ytkowanych................................ 41 Wytyczna 11. Ukrywaj informacje .............................................................................................. 43 Wytyczna 12. Niepotrzebna rywalizacja to niezdrowa rywalizacja ............................................. 45 Wytyczna 13. Zagwarantuj opiek nad zasobami przez obiekty. Stosuj RAII i inteligentne wskazniki .................................................................... 49 RozdziaB 3. Styl kodowania.........................................................................................53 Wytyczna 14. Lepsze bBdy kompilacji i konsolidacji od bBdów czasu wykonania ................... 54 Wytyczna 15. Nie bój si stosowania const ................................................................................. 57 Wytyczna 16. Unikaj makrodefinicji ........................................................................................... 59 Wytyczna 17. Unikaj  magicznych numerków .......................................................................... 62 Wytyczna 18. Zmienne deklaruj najbardziej lokalnie, jak to mo|liwe......................................... 64 Wytyczna 19. Ka|da zmienna powinna zosta zainicjalizowana................................................. 66 Wytyczna 20. Unikaj rozwlekBych funkcji, wystrzegaj si gBbokich zagnie|d|eD ..................... 69 Wytyczna 21. Unikaj zale|no[ci inicjalizacji w ró|nych jednostkach kompilacji ....................... 71 4 Spis tre[ci Wytyczna 22. Redukuj zale|no[ci definicyjne i unikaj zale|no[ci cyklicznych .......................... 73 Wytyczna 23. Niech pliki nagBówkowe bd samowystarczalne................................................. 75 Wytyczna 24. Pamitaj o wewntrznych barierach plików nagBówkowych, unikaj barier zewntrznych ................................................................................... 77 RozdziaB 4. F nkcje i operatory...................................................................................79 Wytyczna 25. Parametry przyjmowa odpowiednio  przez warto[, (inteligentne) wskazniki albo referencje ............................................................... 80 Wytyczna 26. Zachowuj naturaln semantyk przeci|anych operatorów .................................. 82 Wytyczna 27. Preferuj kanoniczne postaci operatorów arytmetycznych i przypisania................ 84 Wytyczna 28. Preferuj kanoniczne postaci operatorów ++ i -- oraz ich wersje przedrostkowe ... 86 Wytyczna 29. Przeci|anie w miejsce niejawnej konwersji typów.............................................. 88 Wytyczna 30. Unikaj przeci|ania operatorów &&, || i operatora , (przecinka) .......................... 90 Wytyczna 31. Nie uzale|niaj poprawno[ci kodu od kolejno[ci ewaluacji argumentów wywoBania funkcji............................................................................ 93 RozdziaB 5. Projektowanie klas i dziedziczenie .............................................................95 Wytyczna 32. Ustal rodzaj definiowanej klasy ............................................................................ 96 Wytyczna 33. Lepsze klasy minimalistyczne ni| monolityczne .................................................. 98 Wytyczna 34. Lepsza kompozycja od dziedziczenia ................................................................. 100 Wytyczna 35. Nie dziedzicz po klasach, które nie zostaBy przewidziane jako bazowe.............. 103 Wytyczna 36. O wy|szo[ci interfejsów abstrakcyjnych ............................................................ 106 Wytyczna 37. Dziedziczenie publiczne daje wymienialno[..................................................... 109 Wytyczna 38. Uprawiaj bezpieczne przesBanianie ..................................................................... 111 Wytyczna 39. Niech metody wirtualne bd niepublicznymi, a publiczne  niewirtualnymi.. 114 Wytyczna 40. Unikaj udostpniania konwersji niejawnych....................................................... 117 Wytyczna 41. SkBadowe klas, z wyjtkiem klas prostych agregatów, powinny by prywatne .. 120 Wytyczna 42. Nie trwoni tego, co wBasne................................................................................ 123 Wytyczna 43. Zachowaj umiar w implementacjach prywatnych............................................... 126 Wytyczna 44. Warto polubi zwykBe funkcje  nieskBadowe i niezaprzyjaznione................... 129 Wytyczna 45. Zawsze udostpniaj komplet: new razem z delete............................................... 131 Wytyczna 46. Je[li przeci|a new dla klasy, to porzdnie  z wszystkimi standardowymi formami operatora............................................................................................... 133 RozdziaB 6. Konstr kcja, destr kcja i kopiowanie.......................................................135 Wytyczna 47. Porzdek inicjalizacji skBadowych danych powinien by zgodny z porzdkiem ich deklaracji ................................................................................ 136 Wytyczna 48. W konstruktorze lepsza inicjalizacja od przypisania........................................... 138 Wytyczna 49. Unikaj wywoBaD metod wirtualnych w konstruktorach i destruktorach .............. 140 Wytyczna 50. Destruktory klasy powinny by albo publiczne i wirtualne, albo niewirtualne i zabezpieczone ...................................................................... 143 Wytyczna 51. Operacje destrukcji, dealokacji i podmiany nigdy nie zawodz.......................... 146 Wytyczna 52. Usuwaj, co skopiujesz......................................................................................... 149 Wytyczna 53. Jawnie udostpniaj i blokuj kopiowanie ............................................................. 151 Spis tre[ci 5 Wytyczna 54. Unikaj skrawania obiektów  rozwa| zastosowanie duplikacji w miejsce kopiowania w klasach bazowych ....................................................... 153 Wytyczna 55. Przyzwyczaj si do kanonicznych implementacji przypisania............................ 156 Wytyczna 56. Tam, gdzie to zasadne, udostpniaj bezpieczn (niezgBaszajc wyjtków) operacj podmiany.............................................................................................. 158 RozdziaB 7. Mod By i przestrzenie nazw......................................................................161 Wytyczna 57. Typ i nieskBadowe funkcje jego interfejsu powinny rezydowa w tej samej przestrzeni nazw .............................................................................. 162 Wytyczna 58. Typy i funkcje, je[li nie s przeznaczone do kooperacji, powinny by rozmieszczone w oddzielnych przestrzeniach nazw ........................................... 165 Wytyczna 59. Wystrzegaj si deklaracji i dyrektyw using w plikach nagBówkowych i plikach kodu zródBowego przed dyrektyw #include........................................ 167 Wytyczna 60. Pami powinna by przydzielana i zwalniana w tym samym module............... 171 Wytyczna 61. Nie definiuj w plikach nagBówkowych jednostek podlegajcych Bczeniu zewntrznemu....................................................................................... 173 Wytyczna 62. Nie pozwalaj na propagacj wyjtków pomidzy moduBami .............................. 176 Wytyczna 63. Interfejs moduBu powinien korzysta z dostatecznie przeno[nych typów ........... 179 RozdziaB 8. Szablony i programowanie ogólnione ......................................................183 Wytyczna 64. Acz zalety polimorfizmu dynamicznego i statycznego...................................... 184 Wytyczna 65. Je[li umo|liwia dostosowywanie, to celowo i jawnie ....................................... 187 Wytyczna 66. Wystrzegaj si specjalizacji szablonów funkcji .................................................. 192 Wytyczna 67. Unikaj przypadkowych uszczegóBowieD kodu w zamierzeniu uniwersalnego.... 195 RozdziaB 9. Wyjtki i obsB ga bBdów ........................................................................197 Wytyczna 68. Asercje [wietnie dokumentuj wewntrzne zaBo|enia i niezmienniki kodu........ 198 Wytyczna 69. Ustal racjonalne zasady obsBugi bBdów i [ci[le ich przestrzegaj........................ 201 Wytyczna 70. Odró|niaj bBdy od stanów nimi nie bdcych.................................................... 204 Wytyczna 71. Projektuj i pisz kod wolny od bBdów................................................................. 208 Wytyczna 72. BBdy najlepiej zgBasza za pomoc wyjtków ................................................... 212 Wytyczna 73. ZgBaszaj warto[ci, przechwytuj referencje .......................................................... 217 Wytyczna 74. BBdy trzeba wBa[ciwie sygnalizowa, obsBugiwa i tBumaczy.......................... 219 Wytyczna 75. Unikaj specyfikacji wyjtków............................................................................. 221 RozdziaB 10. Kontenery STL......................................................................................225 Wytyczna 76. Domy[lnie stosuj kontener vector. Inne dobieraj odpowiednio do potrzeb......... 226 Wytyczna 77. Stosuj vector w miejsce tablic............................................................................. 229 Wytyczna 78. W wymianie danych z interfejsami spoza C++ stosuj vector (i string::c_str) ..... 231 Wytyczna 79. W kontenerach najlepiej przechowywa albo warto[ci, albo inteligentne wskazniki do nich.................................................................... 233 Wytyczna 80. Sekwencj najlepiej rozwija metod push_back ............................................... 235 Wytyczna 81. Od operacji na pojedynczych elementach lepsze s operacje na sekwencjach.... 237 Wytyczna 82. Do faktycznego przycinania kontenerów i faktycznego usuwania elementów najlepiej stosowa sprawdzone idiomy ............................................................... 239 6 Spis tre[ci RozdziaB 11. Algorytmy STL......................................................................................241 Wytyczna 83. Korzystaj z udogodnieD kontrolnych implementacji STL................................... 242 Wytyczna 84. Algorytmy s lepsze od ptli............................................................................... 245 Wytyczna 85. Wybieraj z STL wBa[ciwe algorytmy wyszukiwania .......................................... 249 Wytyczna 86. Wybieraj z STL odpowiednie algorytmy sortowania.......................................... 251 Wytyczna 87. Predykaty powinny by funkcjami czystymi ...................................................... 254 Wytyczna 88. W wywoBaniach algorytmów miejsce funkcji powinny zajmowa obiekty funkcyjne ............................................................................................... 256 Wytyczna 89. Zadbaj o poprawno[ obiektów funkcyjnych...................................................... 258 RozdziaB 12. BezpieczeDstwo typów..........................................................................261 Wytyczna 90. Zamiast przeBczania pomidzy typami stosuj polimorfizm ............................... 262 Wytyczna 91. Polegaj na typach, nie na reprezentacjach........................................................... 265 Wytyczna 92. Unikaj rzutowania reinterpret_cast ..................................................................... 267 Wytyczna 93. Unikaj rzutowania static_cast na wskaznikach ................................................... 269 Wytyczna 94. Zachowuj const przy rzutowaniu ........................................................................ 271 Wytyczna 95. Nie korzystaj z rzutowania znanego z C ............................................................. 273 Wytyczna 96. Nie wolno brutalnie kopiowa obiektów typów innych ni| proste POD............. 276 Wytyczna 97. Unie nie sBu| do reinterpretacji reprezentacji .................................................... 278 Wytyczna 98. Nie stosuj zmiennych list argumentów (trzykropków)........................................ 280 Wytyczna 99. Nie korzystaj z niepoprawnych obiektów i niebezpiecznych funkcji.................. 282 Wytyczna 100. Nie wykorzystuj tablic polimorficznie.............................................................. 284 Dodatek A Bibliografia.............................................................................................287 Dodatek B Pods mowanie .......................................................................................295 Skorowidz ...............................................................................................................313 RozdziaB 2. Styl projektowy GBupcy ignoruj zBo|ono[. Pragmatycy od niej cierpi. Niektórzy potrafi jej unika. Geniusze za[ j eliminuj  Alan Perlis Ale wiedziaBem te|, i zapomniaBem, o powiedzeniu Hoare a o tym, |e przedwczesna optymalizacja to zródBo wszelakiego zBa w programowaniu  Donald Knuth, z The Errors of Tex [Knuth98] Trudno w peBni rozdzieli styl kodowania od stylu projektowania. Dlatego w tym roz- dziale postarali[my si uwzgldni te wytyczne, które umykaj uwadze, kiedy mowa o wBa[ciwym kodowaniu. Niniejszy rozdziaB po[wicony jest zasadom i praktykom dajcym si zastosowa szerzej ni| do pojedynczej klasy czy funkcji. Klasycznym przykBadem jest zachowanie równo- wagi pomidzy prostot a przejrzysto[ci kodu (patrz wytyczna 6.) czy unikanie przed- wczesnej optymalizacji (wytyczna 8.), a tak|e przedwczesnej pesymizacji (wytyczna 9.). Owe trzy wytyczne mo|na stosowa nie tylko na poziomie kodowania funkcji, ale równie| na poziomie wy|szym, obejmujcym kwestie projektowania klas i moduBów oraz decyzje co do architektury aplikacji (owe wytyczne obowizuj wszystkich pro- gramistów  uwa|ajcy inaczej powinni zerkn raz jeszcze na stwierdzenie Donalda Knutha i sprawdzi, kogó| on z kolei cytowaB). Wiele wytycznych z tego i nastpnych rozdziaBów odnosi si do aspektów zarzdza- nia zale|no[ciami  kamienia wgielnego in|ynierii oprogramowania i równocze[nie zagadnienia powracajcego w tej ksi|ce wielokrotnie. Pomy[l przez chwil nad dowoln dobr technik in|ynierii oprogramowania  dowoln dobr technik. Jakakolwiek by ona byBa, w ten czy inny sposób polega na redukcji zale|no[ci. Dziedziczenie? Zmniejsza zale|no[ kodu pisanego pod ktem klasy bazowej od klas pochodnych. Redukcja liczby zmiennych globalnych? To jawna redukcja rozcigBych zale|no[ci w stosunku do widocznych rozlegle danych. Abstrakcja? To eliminacja zale|no[ci pomidzy kodem manipulujcym pojciami a kodem implementujcym te pojcia. 28 RozdziaB 2. Styl projektowy Ukrywanie informacji (hermetyzacja)? Czyni kod u|ytkownika mniej zale|nym od szczegóBów implementacyjnych danej jednostki. WBa[ciwa waga przykBadana do zarzdzania zale|no[ciami przejawia si te| w unikaniu wspólnych danych o stanie (wytyczna 10.), zaleceniu hermetyzacji informacji (wytyczna 11.) i wielu innych. Naszym zdaniem najcenniejsz porad w tym rozdziale zawiera wytyczna 6.   Przede wszystkim poprawno[, prostota i przejrzysto[ . W istocie, nic doda, nic uj. Wytyczna 5. Jednej jednostce jedno zadanie 29 Wytyczna 5. Jednej jednostce jedno zadanie Wytyczna 5. Jednej jednostce jedno zadanie Streszczenie Lepiej robi jedn rzecz, a dobrze. Wedle tej zasady nale|aBoby nadawa poszczególnym jednostkom programu (zmiennym, klasom, funkcjom, przestrzeniom nazw, moduBom, bibliotekom) jasno okre[lone i równocze[nie ograniczone zadania. W miar rozrostu jednostki zakres jej zadaD w sposób naturalny si zwiksza, nie powinien jednak obej- mowa coraz to nowych obszarów. Uzasadnienie Powiada si, |e dobry pomysB na biznes to taki, który mo|na uj w jednym zdaniu. Podobna reguBa tyczy si jednostek programu, które powinny mie konkretne i jasno okre[lone zadania. Jednostka odpowiadajca za wicej ni| jedno zadanie jest zwykle nieproporcjonalnie trudniejsza w u|yciu ni| zestaw jednostek prostszych o mniejszej odpowiedzialno[ci, poniewa| jej implementacja obejmuje wicej ni| tylko sum intelektualnego wysiBki, zBo|ono[ci i bBdów w stosunku do jej poszczególnych skBadowych funkcjonalnych. Taka jednostka jest wiksza (zwykle niepotrzebnie) i trudniejsza do stosowania i po- nownego wykorzystania. Zwykle te| jednostka taka udostpnia okrojone interfejsy ka|dego z zadaD  okrojone z racji cz[ciowego pokrywania si ró|nych obszarów zadaniowych i rozmycia wizji implementacji ka|dego z nich. Jednostki o Bczonych zadaniach s zwykle trudniejsze z punktu widzenia projekto- wego i implementacyjnego.  Mnoga odpowiedzialno[ oznacza wtedy zazwyczaj  mnog osobowo[  kombinacyjn liczb ró|nych mo|liwych stanów i zachowaD. Dlatego zalecamy stosowanie prostych i jasnych, jednozadaniowych funkcji (patrz te| wytyczna 39.), prostych klas oraz moduBów o [ci[le ograniczonym zakresie zadaD. Abstrakcje wy|szego poziomu nale|y konstruowa z prostszych abstrakcji ni|szego poziomu. Nie warto w |adnym razie grupowa wielu abstrakcji niskiego poziomu w wikszym i bardziej zBo|onym konglomeracie niskiego poziomu. Implementacja zBo|onego zachowania na bazie szeregu prostszych jest bowiem Batwiejsza ni| imple- mentacja odwrotna. PrzykBady PrzykBad 1.  wywoBanie . W standardowym jzyku C to jeden z typowych przykBadów uBomnego projektu. Funkcja ma zdecydowanie za du|o zadaD: dla wskaznika pustego przydziela pami, dla zerowego argumentu roz- miaru zwalnia wskazywan pami, za[ dla pozostaBych warto[ci argumentów zmienia 30 RozdziaB 2. Styl projektowy rozmiar przydzielonej pamici, przy czym nowy przydziaB w cz[ci pokrywa si w prze- strzeni adresowej z poprzednim, a je[li jest to niemo|liwe, wykonywany jest zupeBnie nowy przydziaB. Trudno o lepszy przykBad wadliwego projektu funkcji. PrzykBad 2.  . Klasa to w standardzie jzyka C++ równie niesBawny przykBad monolitycznego projektu klasy. Klasa ta zostaBa rozepchana zbyt wielk liczb (nawet u|ytecznych i przyjemnych) dodatków  przez to, cho aspiruje do miana kontenera, nie jest nim do koDca, nie mo|e bowiem wybra pomidzy indeksowaniem a iteracj i równocze[nie powiela wiele standardowych algorytmów, nie zostawiajc za to za wiele miejsca na rozszerzenia (patrz przykBad do wytycznej 44.). yródBa [Henney02a] [Henney02b] [McConnell93] §10.5 [Stroustrup00] §3.8, §4.9.4, §23.4.3.1 [Sutter00] §10, §12, §19, §23 [Sutter02] §1 [Sutter04] §37 40 Wytyczna 6. Przede wszystkim poprawno[, prostota i przejrzysto[ 31 Wytyczna 6. Przede wszystkim poprawno[, prostota i przejrzysto[ Wytyczna 6. Przede wszyst kim poprawno[, pros tota i przejrzysto[ Streszczenie Wedle zasady KISS (Keep It Simple Software  parafraza Keep It Simple, Stupid, czyli  jak najpro[ciej, gBupku ) im pro[ciej, tym lepiej. Proste jest niemal zawsze lepsze od zBo|onego. Przejrzyste za[ jest lepsze od niejasnego. No i bezpieczne jest lepsze od niebezpiecznego (patrz wytyczne 83. i 99.). Uzasadnienie Trudno przeceni znaczenie prostoty projektu i przejrzysto[ci kodu. Programista two- rzcy kod czytelny i zrozumiaBy bdzie cieszyB si wdziczno[ci ze strony przyszBego opiekuna tego kodu. Powiniene[ przy tym pamita, |e opiek nad kodem czsto spra- wuj jego twórcy i, majc to na uwadze, dba o swoje samopoczucie w przyszBo[ci. Std klasyczne prawdy w rodzaju: Programy musz by pisane tak, aby daBy si czyta przez ludzi, ewentualnie od czasu do czasu wykonywa przez maszyny  Harold Abelson i Gerald Jay Sussman Pisz programy przede wszystkim dla ludzi, potem dla komputerów  Steve McConnell NajtaDszymi, najszybszymi i najbardziej niezawodnymi komponentami systemu komputerowego s te, których w nim nie ma  Gordon Bell Owe brakujce komponenty s równie| najdokBadniejsze (nigdy si nie myl), najbezpieczniejsze (nie da si do nich wBama) i najprostsze w projektowaniu, dokumentowaniu, testowaniu i konserwacji. Nie sposób przeceni prostoty projektowej  Jon Bentley Wiele wytycznych prezentowanych w tej ksi|ce ma ukierunkowa czytelnika na kod i projekty Batwe w modyfikacji; przejrzysto[ i zrozumiaBo[ to najbardziej po|dane cechy prostych w konserwacji i rozbudowie programów. Trudno zmieni to, czego si nie rozumie. Najsilniejsza sprzeczno[ zachodzi pomidzy przejrzysto[ci kodu a jego optymaliza- cj (patrz wytyczne 7., 8. i 9.). Kiedy (a nie je|eli!) staniesz w obliczu pokusy przed- wczesnej optymalizacji kodu pod ktem wydajno[ci, a kosztem przejrzysto[ci, przy- pomnij sobie sens wytycznej 8.  du|o Batwiej jest przyspieszy poprawny program, ni| poprawi szybki. 32 RozdziaB 2. Styl projektowy Unikaj wic  zauBków jzyka programowania i stosuj zawsze najprostsze z efektyw- nych technik. PrzykBady PrzykBad 1.  unikaj zbdnego (cho efektownego) przeci|ania operatorów. Jedna z (niepotrzebnie) udziwnionych bibliotek graficznego interfejsu u|ytkownika wyma- gaBa, celem dodania do widgetu elementu sterujcego , napisania wyra|enia (zobacz wytyczn 26.). PrzykBad 2.  w roli parametrów konstruktorów stosuj zmienne nazwane, nie tymcza- sowe. Pozwala to na uniknicie niejednoznaczno[ci deklaracji. Pozwala te| na lepsz prezentacj zadania realizowanego przez kod i tym samym uproszczenie konserwacji programu. Jest te| niejednokrotnie bezpieczniejsze (zobacz wytyczne 13. i 31.). yródBa [Abelson96] [Bentley00] §4 [Cargill92] pp.91 93 [Cline99] §3.05 06 [Constan- tine95] §29 [Keffer95] p. 17 [Lakos96] §9.1, §10.2.4 [McConnell93] [Mey- ers01] §47 [Stroustrup00] §1.7, §2.1, §6.2.3, §23.4.2, §23.4.3.2 [Sutter00] §40 41, §46 [Sutter04] §29 Wytyczna 7. Jak i kiedy kodowa z wzgldnieniem skalowalno[ci 33 Wytyczna 7. Jak i kiedy kodowa z uwzgldnieniem skalowalno[ci Wytyczna 7. Jak i kiedy kodowa z uw zg ldnieniem s kalowalno [ci Streszczenie Wystrzegaj si wybuchowego rozrostu kodu  unikajc przedwczesnej optymalizacji, kontroluj równocze[nie zBo|ono[ asymptotyczn kodu. Algorytmy dziaBajce na danych u|ytkownika powinny cechowa si liniow zBo|ono[ci, czyli liniowym przyrostem czasu wykonania przy przyro[cie ilo[ci przetwarzanych danych. Tam, gdzie optyma- lizacja oka|e si niezbdna, i zwBaszcza gdy zostanie wymuszona zwikszeniem ilo[ci danych, skupiaj si raczej na uzyskaniu sensownej zBo|ono[ci obliczeniowej algorytmu ni| na urywaniu tu i ówdzie po jednej instrukcji maszynowej. Uzasadnienie Niniejsza wytyczna ilustruje punkt równowagi pomidzy wytycznymi 8. i 9. ( unikaj przedwczesnej optymalizacji i  unikaj przedwczesnej pesymizacji) . Z tego wzgldu t wytyczn do[ ci|ko sformuBowa tak, aby nie myli jej sensu z sensem wytycznej 8. Ale do rzeczy. Oto tBo zagadnienia: pojemno[ci pamici ulotnych i dysków twardych rosn wykBad- niczo; w latach od 1988 do 2004 pojemno[ dysków rosBa o 112 procent rocznie (co daje w cigu dekady wzrost blisko 1900-krotny), podczas gdy prawo Moore a zakBada przyrost zaledwie 59-procentowy (100-krotny w cigu dekady). Jedn z konsekwencji tej dynamiki jest to, |e czynno[ci realizowane dzi[ przez kod mog jutro obejmowa znacznie wiksze ilo[ci danych  znacznie wiksze. Je[li stosowane do ich przetwa- rzania algorytmy bd cechowa si kiepsk asymptotyczn zBo|ono[ci obliczeniow, wcze[niej czy pózniej przestan si nadawa do wykorzystywania nawet na najwydaj- niejszych systemach komputerowych  to tylko kwestia ilo[ci danych, którymi te algorytmy bd  karmione . Obrona przed t wtpliw karier algorytmu polega na unikaniu  wbudowywania w projekt takich elementów, które w obliczu konieczno[ci przetwarzania plików wikszych ni| dzi[ przewidywane (wikszych baz danych, wikszej liczby pikseli, wikszej liczby okien, wikszych szybko[ci transmisji) oka| si jego wskimi gardBami. W przypadku biblioteki standardowej jzyka C++ elementami zabezpieczajcymi przyszBo[ s choby gwarancje co do zBo|ono[ci obliczeniowej algorytmów i opera- cji na kontenerach. Oto wniosek: nie powinni[my przedwcze[nie optymalizowa programu przez zastosowa- nie w nim mniej przejrzystego algorytmu, je[li spodziewany przyrost ilo[ci przetwa- rzanych danych nie jest pewny. Ale równie niewskazana jest przedwczesna pesymizacja 34 RozdziaB 2. Styl projektowy algorytmu, polegajca na zamykaniu oczu na jego niekorzystn asymptotyczn zBo|ono[ obliczeniow (rozumian jako koszt wykonania obliczeD w funkcji liczby przetwa- rzanych elementów). Uzasadnienie to mo|na by podzieli na dwie cz[ci. Po pierwsze, nawet przed poznaniem docelowego woluminu danych i oszacowaniem, czy jego rozmiar bdzie miaB istotny wpByw na wydajno[ danego kodu, nale|y unika takich algorytmów operujcych na danych u|ytkownika, które kiepsko si skaluj, chyba |e dziki zastosowaniu takiego algorytmu zyskamy na czytelno[ci albo przejrzysto[ci kodu (patrz wytyczna 6.). Zbyt czsto programi[ci s jednak zaskakiwani  pisz kod z my[l o tym, |e nigdy nie przyjdzie mu operowa na olbrzymich zbiorach danych (i w dziewiciu przypadkach na dziesi nie myl si). Jednak w tym jednym na dziesi przypadku wpadaj w puBapk braku wydajno[ci  zdarzaBo si to nam i z pewno[ci zdarzy si (prdzej czy pózniej) równie| czytelnikowi. Z pewno[ci mo|na wtedy opracowa poprawk i dostarczy j klientom, ale znacznie lepiej byBoby unikn tego rodzaju zakBopotania i wysiBku. Wic, je[li pozostaBe cechy kodu (w tym czytelno[ i przejrzysto[ kodu) na tym nie ucierpi, od pocztku warto: w miejsce tablic o staBych rozmiarach stosowa elastyczne, przydzielane dynamicznie struktury danych. Statyczne tablice  wiksze, ni| kiedykolwiek bd potrzebne to obraza dla poprawno[ci i bezpieczeDstwa programu (patrz wytyczna 77.). S one do zaakceptowania jedynie wtedy, kiedy rozmiar danych jest faktycznie ustalony i staBy! zna faktyczn zBo|ono[ algorytmu  szczególnie grozne s takie algorytmy, których zBo|ono[ obliczeniowa jest z pozoru liniowa, ale które wywoBuj wewntrznie inne operacje o liniowej zBo|ono[ci, dajc w efekcie zBo|ono[ kwadratow (przykBad w wytycznej 81.). wszdzie tam, gdzie to mo|liwe, preferowa algorytmy o zBo|ono[ci liniowej i lepszej  najlepsza byBaby staBa zBo|ono[ w funkcji liczby elementów, jak w przypadku operacji na kontenerach albo operacji wyszukiwania w tabeli haszowanej (patrz wytyczne 76. i 80.). NiezBa jest zBo|ono[ logarytmiczna (O(logN)), osigana midzy innymi w operacjach na kontenerach i czy operacjach i z iteratorami swobodnego dostpu (patrz wytyczne 76., 85. i 86.). Do zaakceptowania jest zBo|ono[ liniowa (O(N)), jak w operacjach albo algorytmie (zobacz wytyczne 76., 81. i 84.). tam, gdzie to zasadne, unika algorytmów o zBo|ono[ci gorszej ni| liniowa  na przykBad w obliczu algorytmu o zBo|ono[ci rzdu O(N log N) albo O(N2) warto spdzi troch czasu na poszukiwaniu rozwizaD o mniejszej zBo|ono[ci obliczeniowej, celem uniknicia puBapki wydajno[ciowej wynikajcej z przewidywanej dynamiki wzrostu ilo[ci przetwarzanych danych. Z tego wBa[nie powodu w wytycznej 81. doradzamy preferowanie metod przetwarzajcych caBe sekwencje elementów (metody te cechuj si zBo|ono[ci liniow) zamiast wywoBaD ich odpowiedników przetwarzajcych pojedyncze elementy (poniewa| w przypadku wywoBania w operacji o liniowej zBo|ono[ci innej takiej operacji otrzymujemy zBo|ono[ kwadratow; patrz te| przykBad 1. w ramach wytycznej 81.). Wytyczna 7. Jak i kiedy kodowa z wzgldnieniem skalowalno[ci 35 nie stosowa nigdy algorytmu wykBadniczego, chyba |e nie ma innego  w obliczu konieczno[ci zastosowania algorytmu o wykBadniczej zBo|ono[ci obliczeniowej nie wolno szczdzi wysiBku na poszukiwania alternatywy, poniewa| w tym przypadku nawet nieznaczne zwikszenie rozmiaru przetwarzanych danych stanowi istn barier wydajno[ciow. Z drugiej strony, po wykonaniu pomiarów dowodzcych, |e optymalizacja jest zasadna i wa|na, zwBaszcza z uwagi na rosnce ilo[ci danych do przetworzenia, powinni[my skupi si na redukcji zBo|ono[ci obliczeniowej, nie próbujc szuka ratunku w po- mniejszych optymalizacjach, urywajcych tu i ówdzie po jednej czy par instrukcji maszynowych. Reasumujc  wszdzie tam, gdzie to mo|liwe, korzystaj z algorytmów o zBo|ono[ci liniowej albo lepszej. Staraj si unika algorytmów o zBo|ono[ci wielomianowej; jak ognia wystrzegaj si za[ algorytmów o zBo|ono[ci wykBadniczej. yródBa [Bentley00] §6, §8, dod. A [Cormen01] [Kernighan99] §7 [Knuth97a] [Knuth97b] [Knuth98] [McConnell93] §5.1 4, §10.6 [Murray93] §9.11 [Sedgewick98] [Stroustrup00] §17.1.2 36 RozdziaB 2. Styl projektowy Wytyczna 8. Wystrzegaj si przedwczesnej optymalizacji Wytyczna 8. Wystrzegaj si przedwczesnej optymalizacji Streszczenie Nie bodzie si chtnego wierzchowca. Przedwczesna optymalizacja jest równie uzale|- niajca, jak bezproduktywna, pierwsza reguBa optymalizacji mówi bowiem: zaniechaj jej. Druga reguBa (dla ekspertów) mówi za[: powstrzymaj si jeszcze. Jedn optymali- zacj trzeba poprzedzi dwoma pomiarami dowodzcymi jej konieczno[ci. Uzasadnienie We wstpie do [Stroustrup00] §6 znajdziemy [wietne cytaty: Przedwczesna optymalizacja to zródBo wszelkiego zBa  Donald Knuth (cytujcy z kolei z Hoare a) Z drugiej strony, nie mo|emy ignorowa efektywno[ci  Jon Bentley Hoare i Knuth maj (jak zwykle) racj (patrz wytyczna 6. i niniejsza). Tak jak i Bentley (wytyczna 9.). Przedwczesn optymalizacj zdefiniowaliby[my jako zwikszanie zBo|ono[ci projektu albo kodu, a przez to zmniejszenie ich czytelno[ci, w imi wydajno[ci, której potrzeba zwikszenia nie zostaBa jeszcze dowiedziona (na przykBad pomiarami i porównaniem ich wyników z zaBo|onymi celami)  jako taka optymalizacja ta nie wnosi do projektu |adnych korzy[ci. Czsto przedwczesna i niepoparta pomiarami optymalizacja, mimo wBo|onego w ni wysiBku, nie daje dosBownie |adnego efektu wydajno[ciowego. Warto wic zapamita, |e: Znacznie Batwiej przyspieszy poprawny program, ni| poprawi szybki! Nie nale|y wic od pocztku skupia si na szybko[ci kodu  w pierwszej kolejno[ci powinna nas interesowa raczej jego przejrzysto[ i czytelno[ (zgodnie z wytyczn 6.). W kodzie czytelnym Batwiej o poprawno[, zrozumienie jego dziaBania, wprowadzanie poprawek i zmian, i wreszcie optymalizacj. Komplikacje, nieodzowne dla optymalizacji, zawsze mo|na wprowadzi pózniej  i tylko wtedy, gdy s niezbdne. Przedwczesna optymalizacja czsto nie daje spodziewanych efektów z dwóch gBównych powodów. Po pierwsze, programi[ci stale myl si w swoich szacunkach co do szybko[ci danego kodu i typowania jego wskich gardeB. Dotyczy to nas, autorów tej ksi|ki, i dotyczy najprawdopodobniej równie| Ciebie. WspóBczesne komputery realizuj Wytyczna 8. Wystrzegaj si przedwczesnej optymalizacji 37 potwornie skomplikowany model maszyny obliczeniowej, obejmujcej niekiedy kilka czy kilkana[cie potoków przetwarzania obsBugiwanych wspóBbie|nie, z rozbudowan hierarchi pamici podrcznych, predykcj rozgaBzieD programu  i wszystko to w jednym procesorze! Kompilatory, bazujce na tych mo|liwo[ciach, równie| staraj si transformowa kod zródBowy tak, aby wynikowy kod maszynowy jak najlepiej wpa- sowaB si w architektur procesora. Dopiero na bazie kompilatora operuje programista, i je[li dla poparcia swoich decyzji ma jedynie nie[cisBe szacunki i swoj intuicj, to szansa, |e wprowadzane przez niego mikrooptymalizacje bd miaBy znaczcy wpByw na program, jest prawie |adna. Jak wida, optymalizacj nale|y koniecznie poprzedzi odpowiednimi pomiarami. Dopóki nie uda si w ten sposób dowie[ istotnej potrzeby optymalizacji, nale|y skupi si na kwestii najwa|niejszej, czyli tworzeniu zrozumia- Bego i czytelnego kodu (je[li kto[ za|da optymalizacji programu, |daj dowodów jej konieczno[ci). Dalej, we wspóBczesnych programach efektywno[ znacznej cz[ci operacji nie jest ju| ograniczana wydajno[ci procesora. Znakomita cz[ z nich znacznie bardziej ogra- niczona jest efektywno[ci dostpu do pamici, szybko[ci transmisji w sieci, czasem dostpu do napdów pamici masowych, czasem oczekiwania na odpowiedz serwera WWW czy serwera baz danych. Wobec tego optymalizacja kodu aplikacji wykonuj- cej wszystkie te operacje spowoduje jedynie, |e aplikacja bdzie szybciej na nie czeka. A to oznaczaBoby, |e programista zmarnowaB sporo czasu, ulepszajc to, co ulepszenia nie wymagaBo, zamiast ulepsza to, co faktycznie kuleje. Oczywi[cie nadejdzie wreszcie ten dzieD, kiedy kod trzeba bdzie nieco zoptymali- zowa. W takim przypadku w pierwszej kolejno[ci nale|y szuka ratunku w zmniej- szeniu zBo|ono[ci obliczeniowej algorytmu (wytyczna 7.) i równocze[nie próbowa hermetyzowa i ogranicza zasig optymalizacji (na przykBad do funkcji albo klasy  patrz wytyczne 5. i 11.) oraz koniecznie opatrzy kod stosownymi komentarzami, wyja[niajcymi bie|ce potrzeby optymalizacji i odnoszcymi si do zastosowanych algorytmów. Powszechnym bBdem pocztkujcych programistów jest pisanie  z dum!  nowego kodu z obsesyjn my[l o jego jak najwikszej wydajno[ci, kosztem czytelno[ci i zro- zumiaBo[ci. Najcz[ciej efektem takiej pracy jest kod spaghetti, który  nawet je[li poprawny  utrudnia analiz i ewentualne modyfikacje (wytyczna 6.) Nie jest przedwczesn optymalizacj przekazywanie argumentów i warto[ci zwracanych przez referencj (patrz wytyczna 25.), preferowanie przedrostkowych wersji operatorów inkrementacji (wytyczna 28.) i tym podobne idiomy, które w naturalny sposób wpaso- wuj si w tok pracy programisty. Nie s to optymalizacje przedwczesne, poniewa| nie komplikuj kodu  pozwalaj za to unikn przedwczesnej jego pesymizacji (patrz wytyczna 9.). PrzykBady PrzykBad  ironia . Oto ilustracja ukrytego kosztu przedwczesnej mikroopty- malizacji. Otó| narzdzia profilujce sBu| do tego, aby na podstawie licznika wywoBaD funkcji informowa programist o tym, które z funkcji nadaj si do rozwijania w miejscu 38 RozdziaB 2. Styl projektowy wywoBania, a nie zostaBy jako takie oznaczone. Niestety, nawet najlepsze takie narzdzie nie bdzie w stanie wskaza takich funkcji, które zostaBy oznaczone jako rozwijane w miejscu wywoBania ( ), cho nie powinny  nie bdzie bowiem |adnej mo|- liwo[ci okre[lenia liczby  wywoBaD tej|e funkcji w kodzie wynikowym. Zbyt czsto programi[ci w imi optymalizacji decyduj si na rozwijanie wielu funkcji w miejscu wywoBania, co maBo kiedy przynosi rzeczywiste korzy[ci (zakBadajc, |e kompilator nie ignoruje zupeBnie sBowa  patrz [Sutter00], [Sutter02] czy [Sutter04]). Wyjtki Twórca kodu biblioteki ma zadanie utrudnione o tyle, |e nie bardzo mo|e przewi- dzie, które z jej elementów bd w przyszBo[ci wykorzystywane w kodzie czuBym na wydajno[ wykonania. Ale nawet twórcy bibliotek powinni poprzedzi optymalizacj testami na szerokiej bazie klientów-u|ytkowników biblioteki. yródBa [Bentley00] §6 [Cline99] §13.01 09 [Kernighan99] §7 [Lakos96] §9.1.14 [Meyers97] §33 [Murray93] §9.9 10, §9.3 [Stroustrup00] §6 (wprowadzenie) [Sutter00] §30, §46 [Sutter02] §12 [Sutter04] §25 Wytyczna 9. Wystrzegaj si przedwczesnej pesymizacji 39 Wytyczna 9. Wystrzegaj si przedwczesnej pesymizacji Wytyczna 9. Wystrzegaj si przedwczesnej pesymizacji Streszczenie Je[li pozostaBe czynniki (jak choby czytelno[ kodu czy jego zBo|ono[) nie ucierpi na tym, to pewne wzorce projektowe, praktyki programistyczne i tym podobne idio- my programistyczne nale|y uzna za o tyle naturalne, |e ich wprowadzenie nie wi|e si dla programisty ze zwikszonym wysiBkiem i niejako same wychodz spod jego palców. Nie uznajemy ich za przedwczesn optymalizacj, a raczej za unikanie nie- potrzebnej pesymizacji. Uzasadnienie Unikanie przedwczesnej pesymizacji nie mo|e oznacza wzrostu efektywno[ci, je[li osiga si go znacznym kosztem. Przedwczesn pesymizacj bdziemy rozumie jako niepotrzebne potencjalne ograniczenia efektywno[ci, takie jak: definiowanie parametrów jako przekazywanych przez warto[ tam, gdzie mo|na by je przekazywa przez referencj (patrz wytyczna 25.); stosowanie przyrostkowych wersji operatorów inkrementacji tam, gdzie mo|na by zastosowa wersje przedrostkowe (patrz wytyczna 28.); wykonywanie przypisaD w ciele konstruktora, a nie w li[cie inicjalizacyjnej (patrz wytyczna 48.). Nie jest równie| przedwczesn optymalizacj redukowanie liczby niepotrzebnych tymczasowych kopii obiektów, zwBaszcza w ptlach wewntrznych i zwBaszcza wtedy, kiedy ta redukcja nie wpBywa na zBo|ono[ kodu. Co prawda wytyczna 18. zachca do deklarowania zmiennych jak najbardziej lokalnie, wskazuje jednak na wyjtki, w obliczu których lepiej deklaracj zmiennej przenie[ poza ptl. W wikszo[ci przypadków takie przesunicia nie maj znaczenia dla przejrzysto[ci kodu, a nawet pozwalaj na lepsze uwidocznienie operacji wykonywanych w ptli i wyodrbnienie niezmienników tej ptli. Oczywi[cie najlepiej w miejsce jawnych ptli stosowa algorytmy STL (patrz wytyczna 84.). Przejrzysto[ godzi si z efektywno[ci przez stosowanie abstrakcji i bibliotek (patrz wytyczne 11. i 36.). Na przykBad, korzystajc ze standardowych elementów bibliotecz- nych jzyka C++ (kontenerów , , , algorytmów czy ), projekto- wanych i implementowanych przez [wiatowej klasy ekspertów, nie tylko zwikszamy przejrzysto[ kodu, ale niejednokrotnie znacznie go przyspieszamy. 40 RozdziaB 2. Styl projektowy Unikanie przedwczesnej pesymizacji jest szczególnie istotne dla twórców bibliotek. Zazwyczaj nie maj oni mo|liwo[ci przewidzenia wszystkich kontekstów, w których ich kod zostanie wykorzystany, powinni wic przesun nieco [rodek ci|ko[ci w kierunku efektywno[ci i moduBowo[ci (przydatno[ci do ponownego wykorzystania), wystrze- gajc si jednak przesady w zwikszaniu efektywno[ci, je[li przyrost ten odczuje jedynie niewielki odsetek potencjalnych u|ytkowników biblioteki. Wyznaczenie punktu ci|ko[ci to oczywi[cie zadanie programisty, ale zgodnie z wytyczn 7., nacisk nale|y poBo|y raczej na uzyskanie rozsdnej skalowalno[ci, ni| na mikrooptymalizacje polegajce na urywaniu pojedynczych cykli procesora. yródBa [Keffer95] pp. 12 13 [Stroustrup00] §6 (wprowadzenie) [Sutter00] §6 Wytyczna 10. Minimaliz j ilo[ danych globalnych i wspóB |ytkowanych 41 Wytyczna 1O. Minimalizuj ilo[ danych globalnych i wspóBu|ytkowanych Wytyczna 10. Min imalizuj ilo [ danych globalnych i wspóBu |yt kowanych Streszczenie WspóBu|ytkowanie oznacza rywalizacj  nale|y wic unika danych wspólnych, zwBaszcza globalnych. Zwikszaj one powizanie kodu kosztem Batwo[ci konserwacji, a niejednokrotnie i wydajno[ci. Uzasadnienie Niniejsza wytyczna jest pewnym uogólnieniem wytycznej 18. Chodzi o unikanie stosowania danych (wizanych zewntrznie) o zasigu pokrywaj- cym si z zasigiem przestrzeni nazw albo wystpujcych w postaci statycznych skBa- dowych klas. Komplikuj one logik programu i u[ci[laj zwizki pomidzy ró|nymi (i, co gorsza, odlegBymi) elementami programu. WspóBu|ytkowanie danych zmniejsza mo|liwo[ci testowania jednostki programu, poniewa| poprawno[ kodu odwoBujcego si do takich danych jest mocno uzale|niona od historii zmian tych danych i warunków wykonania dalszego, nieznanego bli|ej kodu, który si pózniej do tych danych odwoBuje. Nazwy obiektów w globalnej przestrzeni nazw za[miecaj t przestrzeD, zwikszajc ryzyko kolizji nazw. Je[li ju| trzeba zastosowa obiekt globalny, obiekt o zasigu pokrywajcym si z za- sigiem przestrzeni nazw albo statyczny obiekt klasy, nale|y starannie go zainicjali- zowa. Porzdek inicjalizacji tego rodzaju obiektów w ró|nych jednostkach kompilacji jest niezdefiniowany i aby zapewni jego poprawno[, trzeba wdro|y specjalne techniki (odsyBamy do zródeB). ReguBy kolejno[ci inicjalizacji s subtelne  lepiej unika koniecz- no[ci zagBbiania si w te subtelno[ci, a je[li jest to niemo|liwe, warto je przynajmniej dobrze pozna i starannie stosowa. Obiekty o zasigu przestrzeni nazw, skBadowe statyczne oraz obiekty dzielone przez wiele wtków albo procesów redukuj zrównoleglenie w [rodowiskach wielowtkowych i wieloprocesorowych i s czstymi wskimi gardBami wydajno[ci i skalowalno[ci (patrz wytyczna 7.). Optuj za zasad  jak najmniej wspólnego  zamiast danych wspólnych (wspóBu|ytkowanych) stosuj komunikacj pomidzy u|ytkownikami danych (np. kolejki komunikatów). CaBo[ sprowadza si za[ do unikania [cisBych zale|no[ci i do minimalizacji interakcji pomidzy klasami (patrz [Cargill92]). 42 RozdziaB 2. Styl projektowy Wyjtki Za wyjtki mo|na uzna takie mechanizmy, jak obiekty , i , implemen- towane celowo jako obiekty globalne. Dalej, np. fabryka (generator obiektów wedBug wzorca projektowego Factory) musi utrzymywa rejestr funkcji do wywoBania celem utworzenia obiektu danego typu i zwykle w programie znajduje si jeden taki rejestr (powinien by on jednak obiektem wewntrznym fabryki, a nie wspóBu|ytkowanym obiektem globalnym; patrz wytyczna 11.). Kod zakBadajcy wspóBu|ytkowanie obiektów przez wiele wtków powinien zawsze sze- regowa wszelkie odwoBania do owych obiektów (patrz wytyczna 12. oraz [Sutter04c]). yródBa [Cargill92] pp.126 136, 169 173 [Dewhurst03] §3 [Lakos96] §2.3.1 [McCon- nell93] §5.1 4 [Stroustrup00] §C.10.1 [Sutter00] §47 [Sutter02] §16, dod. A [Sutter04c] [SuttHysl03] Wytyczna 11. Ukrywaj informacje 43 Wytyczna 11. Ukrywaj informacje Wytyczna 11. U krywaj informacje Streszczenie Nie eksponuj wewntrznych informacji jednostki stanowicej abstrakcj. Uzasadnienie Minimalizacja zale|no[ci pomidzy wywoBujcym, manipulujcym pewn abstrakcj, a wywoBywanym, czyli implementacj tej abstrakcji, wymaga ukrywania danych we- wntrznych tej implementacji. W przeciwnym razie wywoBujcy mo|e si do owych informacji odwoBywa (albo, co gorsza, manipulowa nimi) z pominiciem implemen- tacji abstrakcji. Eksponowa nale|y raczej sam abstrakcj (nawet, je[li ma ona jedynie posta akcesorów - ), a nie jej dane. Ukrywanie informacji zmniejsza koszt projektu, skraca harmonogram realizacji lub (i) ryzyko jego przekroczenia, dziki: ograniczaniu zasigu zmian  ukrywanie informacji redukuje efekt domina w przypadku zmian, a wic redukuje ich koszt. wzmocnieniu niezmienników  przez ograniczanie kodu odpowiedzialnego za zachowanie (albo i zBamanie) niezmienników programu (patrz wytyczna 41.). Nie powinno si eksponowa danych |adnej jednostki, która stanowi abstrakcj (patrz te| wytyczna 10.), konkretne dane s bowiem charakterystyczne jedynie dla jednego z mo|liwych wcieleD abstrakcji, jednego z jej konceptualnych stanów. Je[li skupi si na koncepcjach, a nie ich reprezentacjach wewntrznych, to dla tej samej abstrakcji i wspólnego interfejsu mo|na udostpni caBkowicie ró|ne implementacje (na przykBad obliczenia z buforowaniem wyników w jednej albo realizowane  w locie w innej), wykorzystujce odmienne reprezentacje wewntrznych danych (na przykBad wspóB- rzdne w ukBadzie biegunowym albo kartezjaDskim). Powszechnie uwa|a si, |e nie nale|y dokonywa ekspozycji skBadowych danych klas przez oznaczanie ich jako publicznych (wytyczna 41.) albo przez udostpnianie ich wskazników czy uchwytów (wytyczna 42.). Tyczy si to jednak równie| jednostek wikszych od klas, takich jak bibliotek, które równie| nie powinny eksponowa danych implementacyjnych. ModuBy i biblioteki powinny raczej udostpnia interfejsy defi- niujce abstrakcje i transfery midzy nimi  pozwala to na bezpieczniejsze komuni- kowanie si z wywoBujcym i mniej [cisBe powizanie wywoBujcego z bibliotek, ni| to ma miejsce przy stosowaniu danych wspóBu|ytkowanych. 44 RozdziaB 2. Styl projektowy Wyjtki Wyjtkiem mo|e by kod testujcy, niejednokrotnie wymagajcy swobodnego dostpu do danych testowanych klas i moduBów. Regule ukrywania danych nie podlegaj równie| agregaty warto[ci (np. znane z jzyka C struktury), stanowice jedynie zlepek danych, dla których nie przewidziano abstrakcji behawioralnej  dane te stanowi wtedy równocze[nie swój wBasny (jedyny) interfejs (zobacz wytyczna 41.). yródBa [Brooks95] §19 [McConnel] §6.2 [Parnas02] [Stroustrup00] §24.4 [SuttHysl04a] Wytyczna 12. Niepotrzebna rywalizacja to niezdrowa rywalizacja 45 Wytyczna 12. Niepotrzebna rywalizacja to niezdrowa rywalizacja Wytyczna 12. Niepotr zebna rywalizacja to niezdrowa rywalizacja Streszczenie BezpieczeDstwo wtkowe to podstawa  je[li aplikacja wykorzystuje wiele wtków czy procesów, programista musi wiedzie, jak ma minimalizowa wspóBu|ytkowanie obiektów (zobacz wytyczna 10.) i jak bezpiecznie u|ytkowa te, które musz pozosta wspólne. Uzasadnienie Wtki to obszerne zagadnienie. Jego waga wymaga potwierdzenia w wydzieleniu dla niego osobnej wytycznej. W ramach jednej takiej wytycznej nie sposób jednak uj wszystkiego, co zwizane z programowaniem wtków, ograniczymy si wic do pod- sumowania kilku kwestii zasadniczych  po szczegóBy odsyBamy za[ do zródeB. Za kwestie najwa|niejsze uwa|amy za[ unikanie zakleszczeD, unikanie zawBaszczania zasobów i unikanie szkodliwej rywalizacji w dostpie do zasobów (i ich uszkodzenia w wyniku niewystarczajcego blokowania). Standard jzyka C++ nie po[wica wtkom ani sBowa. Mimo tego jzyk ten jest ruty- nowo i powszechnie wykorzystywany do pisania solidnych, wielowtkowych aplikacji. Je[li wic Twój program dzieli dane pomidzy wtki, niech robi to bezpiecznie: Sprawdz w dokumentacji platformy docelowej dostpno[ elementarnych mechanizmów synchronizacji lokalnej  od niepodzielnych maszynowych operacji na warto[ciach caBkowitych po bariery pamiciowe i blokady wewntrzprocesowe i midzyprocesowe. Spróbuj uj owe elementarne mechanizmy we wBasnych abstrakcjach  to dobry pomysB, zwBaszcza je[li program ma docelowo dziaBa na wielu platformach. Alternatywnie mo|na skorzysta z gotowych bibliotek tego rodzaju (np. biblioteki pthreads [Butenhof97]). Upewnij si, |e wykorzystywane typy mog by bezpiecznie stosowane w programie wielowtkowym  w szczególno[ci ka|dy z takich typów powinien: gwarantowa niezale|no[ obiektów niewspóBu|ytkowanych. Dwa wtki powinny móc swobodnie korzysta z dwóch ró|nych obiektów. dokumentowa wymagania odno[nie do wywoBujcego, je[li ten chce odwoBywa si do tego samego obiektu z ró|nych wtków. Cz[ typów wymaga szeregowania dostpu do tak wspóBu|ytkowanych obiektów, inne obchodz si bez takiej synchronizacji. W przypadku tych ostatnich brak konieczno[ci blokowania i synchronizacji dostpu wynika zazwyczaj 46 RozdziaB 2. Styl projektowy z projektu typu, ewentualnie z zastosowania synchronizacji wewntrznej  w którym to przypadku programista powinien by [wiadom ograniczeD owego wewntrznego blokowania i zna jego szczegóBowo[. Zauwa|, |e powy|sze reguBy dotycz wszelkich typów, bez wyró|niania typów BaDcuchowych, kontenerów, kontenerów STL czy jakichkolwiek innych (zauwa|yli[my bowiem, |e niektórzy autorzy wyró|niaj tutaj kontenery STL jako w jaki[ sposób szczególne, tymczasem obiekty te nie wyró|niaj si niczym w tym zakresie). W szczególno[ci, gdy zamierzamy wykorzysta w programie wielowtkowym komponenty biblioteki standardowej, powinni[my sprawdzi w dokumentacji biblioteki, czy jej implementacja daje tak mo|liwo[. Tworzc wBasne typy przeznaczone do wykorzystywania w programach wielowtko- wych, musimy zadba o te same dwa elementy: po pierwsze, zagwarantowa niezale|- no[ (niewymagajc blokowania) ró|nych egzemplarzy tego danego typu (podpowiedz: typ z modyfikowaln skBadow statyczn nie daje takiej gwarancji); po drugie, udoku- mentowa wymagania co do u|ytkowników typu w zakresie stosowania wspólnego obiektu tego typu w ró|nych wtkach. W tej kwestii zasadnicze znaczenie ma problem rozBo|enia pomidzy klas a jej u|ytkownikami odpowiedzialno[ci za poprawne wyko- nanie programu. Mamy w tym zakresie trzy podstawowe mo|liwo[ci: Blokowanie zewntrzne  za blokowanie odpowiedzialny jest wywoBujcy (u|ytkownik). W tym ukBadzie kod korzystajcy z obiektu jest w peBni odpowiedzialny za synchronizacj odwoBaD do tego obiektu, je[li jest on wykorzystywany w wielu wtkach. Z blokowania zewntrznego korzystaj zazwyczaj typy BaDcuchowe (czsto uciekaj si te| do niezmienno[ci, zobacz opis trzeciej opcji). Blokowanie wewntrzne  ka|dy obiekt samodzielnie szereguje odwoBania do niego, zwykle przez blokady wszystkich metod publicznych, zwalniajce u|ytkowników z odpowiedzialno[ci za synchronizacj dostpu do obiektu. PrzykBadowo, w kolejkach producentów-konsumentów stosowane jest blokowanie wewntrzne, poniewa| obiekty te s z zasady przeznaczone do wspóBu|ytkowania przez wtki i ich interfejsy s zaprojektowane z uwzgldnieniem blokowania niezbdnego do bezpiecznego wykonania ka|dej z metod. Ta opcja jest wBa[ciwa w przypadkach, kiedy z góry wiadomo, |e: obiekty danego typu bd wykorzystywane niemal wyBcznie jako wspóBu|ytkowane w wielu wtkach  je[li nie jest to pewne, blokowanie wewntrzne bdzie w znacznej cz[ci zbdne. Wypada zauwa|y, |e niewiele typów speBnia to wymaganie  znakomita wikszo[ obiektów nawet w programie silnie wielowtkowym nie podlega wspóBu|ytkowaniu przez wtki (co nie jest bynajmniej zarzutem  zobacz wytyczna 10.). blokowanie poszczególnych metod pozwoli osign odpowiedni szczegóBowo[ synchronizacji, odpowiedni dla wikszo[ci u|ytkowników. W szczególno[ci interfejs typu powinien faworyzowa operacje  gruboziarniste , samowystarczalne. Je[li typowy u|ytkownik bdzie musiaB z zasady blokowa kilka operacji zamiast jednej, to indywidualne blokowanie metod nie zda egzaminu. Bdzie musiaBo by poparte Wytyczna 12. Niepotrzebna rywalizacja to niezdrowa rywalizacja 47 blokowaniem ogólniejszym (prawdopodobnie zewntrznym, pozostajcym w gestii u|ytkownika), pozwalajcym na szeregowanie nie pojedynczych operacji, a caBych transakcji. Wezmy choby typ kontenera zwracajcego iterator i problem uniewa|nienia iteratora przed jego u|yciem. Albo typ udostpniajcy w postaci metody algorytm zwracajcy wynik, którego poprawno[ zostanie zniesiona w czasie pomidzy utworzeniem obiektu a wywoBaniem metody. Albo kiedy u|ytkownik obiektu pewnego typu zechce wykona operacj (wicej przykBadów w [Sutter02]). W takich przypadkach u|ytkownik bdzie musiaB  mimo wewntrznego szeregowania dostpu do poszczególnych metod  wdro|y na wBasn rk blokad, której czas |ycia obejmuje wiele kolejnych wywoBaD metod. W takim ukBadzie ich blokowanie wewntrzne traci zupeBnie sens. Jak wida, wewntrzne blokowanie ma [cisBy zwizek z publicznym interfejsem typu: jest wBa[ciwe, kiedy poszczególne operacje tego interfejsu s kompletne, czyli kiedy poziom abstrakcji typu zostanie podniesiony i wyra|ony bardziej precyzyjnie (na przykBad  kolejka producent-konsument zamiast ogólnego  tablica ). Interfejsy te Bcz elementarne manipulacje na typie do postaci operacji znaczcych i u|ytecznych samych w sobie. Je[li liczba takich kombinacji jest nie do przewidzenia i nie sposób wychwyci kombinacji najczstszych, celem wyodrbnienia ich do  wikszych operacji, mamy dwie mo|liwo[ci: (a) zastosowa model oparty na wywoBaniach zwrotnych (kiedy u|ytkownik wywoBuje pojedyncz metod, przekazujc do niej obiekt funkcyjny bdz funkcj, która ma posBu|y do realizacji rozleglejszego zadania  patrz wytyczne od 87. do 89.) albo (b) wyeksponowa mechanizmy blokowania w interfejsie. Bez blokowania, za to z zaBo|eniem niezmienno[ci (w przypadku obiektów niemodyfikowalnych). Mo|na tak zaprojektowa typy obiektów, aby ich blokowanie nie byBo w ogóle potrzebne (patrz zródBa). PrzykBadem takiego projektu s obiekty niemodyfikowalne  szeregowanie dostpu do nich jest zbdne, poniewa| nie mo|na ich zmienia. PrzykBadem mo|e by typ niemodyfikowalnego BaDcucha znaków, którego obiektu nie mo|na zmienia w czasie |ycia, a ka|da operacja na BaDcuchu powoduje utworzenie nowego obiektu z nowym BaDcuchem znaków. Warto pamita, |e u|ytkownik niekoniecznie musi dysponowa wiedz co do szcze- góBów implementacji danego typu (zgodnie z wytyczn 11.). Je[li Twój typ wykorzy- stuje ukryte mechanizmy zarzdzajce wspóBu|ytkowaniem obiektów (np. opóznianie kopiowania, tzw.  kopiowanie przy zapisie ), nie musisz bra odpowiedzialno[ci za wszelkie mo|liwe kwestie zwizane z wielowtkowo[ci, ale nie mo|esz zignorowa odpowiedzialno[ci za zapewnienie bezpieczeDstwa wtkowego w stopniu wystarcza- jcym do zapewnienia poprawno[ci odwoBaD do obiektu przez u|ytkownika, je[li ten dopeBni swoich zwykBych obowizków  typ powinien by co najmniej tak bezpieczny, jak byBby, gdyby nie stosowaB utajonych mechanizmów wspóBu|ytkowania (zobacz [Sutter04c]). Wszystkie prawidBowo zdefiniowane typy powinny pozwala na manipu- lowanie osobnymi, niezale|nymi egzemplarzami z poziomu niezale|nych wtków bez potrzeby jakiejkolwiek synchronizacji pomidzy tymi egzemplarzami. 48 RozdziaB 2. Styl projektowy Twórca biblioteki przeznaczonej do powszechnego u|ytku powinien szczególnie rozwa- |y zabezpieczenie obiektów biblioteki przed interakcjami w [rodowisku wielowtko- wym. Powinien do tego podej[ w sposób opisany powy|ej, ale tak, aby zabezpieczenia te nie powodowaBy znacznych narzutów w [rodowiskach wielowtkowych. Je[li na przykBad piszesz bibliotek zawierajc typ stosujcy kopiowanie przy zapisie i z tego wzgldu wykorzystujcy równie| jakie[ wewntrzne blokady, blokady te nale|y tak zaaran|owa, aby w kompilacjach dla [rodowisk jednowtkowych byBy niewidoczne (mo|na uciec si wtedy do dyrektyw i pustych implementacji). ZakBadajc wiele blokad, powiniene[ unika zakleszczeD i ukBada kod tak, aby we wszystkich miejscach pozyskiwania tego| kompletu blokad kolejno[ ich zakBadania byBa zawsze taka sama (zwalnianie blokad mo|e by wtedy realizowane w dowolnym porzdku). Rozwizaniem problemu staBej kolejno[ci zakBadania blokad mo|e by ich zakBadanie wedBug rosncych adresów w pamici  bazujc na adresach, mo|esz Batwo ustali porzdek blokowania wspólny dla caBej aplikacji. yródBa [Alexandrescu02a] [Alexandrescu04] [Butenhof97] [Henney00] [Henney01] [Meyers04] [Shmidt01] [Stroustrup] §14.9 [Sutter02] §16 [Sutter04c] Wytyczna 13. Zagwarant j opiek nad zasobami przez obiekty. Stos j RAII& 49 Wytyczna 13. Zagwarantuj opiek nad zasobami przez obiekty. Stosuj RAll i inteligentne wskazniki Wytyczna 13. Zagwarantuj opiek nad za sobami przez obie kty. S tosuj RAII& Streszczenie Nie walaj rk, je[li masz narzdzia  idiom  pozyskanie zasobu to jego inicjalizacja (RAII, od resource acquisition is initialization) to [wietne narzdzie poprawnej obsBugi zasobów. RAII pozwala kompilatorowi na udostpnianie silnych i automatycznych gwarancji, które w innych jzykach wymagaj karkoBomnych sztuczek programistycz- nych. Przydzielajc surowy zasób, bezzwBocznie przeka| go do obiektu, który ma by jego dysponentem. I nigdy nie przydzielaj wicej ni| jednego zasobu w pojedynczej instrukcji. Uzasadnienie Jzyk C++, wymuszajcy symetri wywoBaD konstruktorów i destruktorów, odwzo- rowuje w niej symetri charakterystyczn dla par funkcji pozyskujcych i zwalniajcych obiekty, takich jak i , i czy operatorów i . Dziki temu przydzielany w pamici stosu (albo implementowany ze zliczaniem odwo- BaD) obiekt z pozyskujcym zasoby konstruktorem i zwalniajcym je destruktorem jest znakomitym narzdziem automatyzacji zarzdzania zasobami. Automatyzacja ta jest prosta w implementacji, elegancka, maBo kosztowna i w swej istocie odporna na bBdy. Jej odrzucenie oznacza obci|enie samego siebie niebanalnym i anga|ujcym zadaniem rcznego parowania wywoBaD pozyskujcych i zwalniajcych zasoby, z uwzgldnieniem wyjtków i wynikajcych z logiki programu rozgaBzieD przepBywu sterowania. Tego rodzaju przywizanie do jzyka C i charakterystycznego dla niego mikrozarzdzania operacjami zwalniania zasobów jest nie do zaakceptowania w jzyku C++, w którym owe czynno[ci s automatyzowane za po[rednictwem RAII. Gdy mamy do czynienia z zasobem wymagajcym parowania wywoBaD funkcji pozy- skujcych i zwalniajcych, powinni[my ów zasób hermetyzowa w obiekcie, skBadajc zadanie zwalniania zasobu na barki jego destruktora. Na przykBad w miejsce wywoBaD pary funkcji i wypadaBoby rozwa|y takie rozwizanie: 50 RozdziaB 2. Styl projektowy  Mo|na równie| korzysta z gotowych bibliotek implementujcych ten schemat (zobacz [Alexandrescu00c]). Implementujc idiom RAII, musimy uwa|a na konstruktory kopiujce i operatory przypisania (zobacz te| wytyczna 49.); generowane przez kompilator wersje tych metod nie bd raczej poprawne. Je[li kopiowanie obiektów hermetyzujcych zasoby nie ma sensu semantycznego, powinni[my jawnie zablokowa mo|liwo[ korzystania z tych operacji, czynic je skBadowymi prywatnymi i niezdefiniowanymi (patrz wytyczna 53.). W pozostaBych przypadkach nale|y zadba o to, aby konstruktor kopiujcy wykonywaB duplikat zasobu (ewentualnie zwikszaB licznik odwoBaD do niego), a operator przypi- sania robiB to samo, po uprzednim ewentualnym zwolnieniu zasobu przetrzymywanego dotychczas. Klasycznym przeoczeniem jest zwolnienie poprzednio przetrzymywanego zasobu przed skutecznym wykonaniem duplikatu nowego (wytyczna 71.). Upewnij si te|, |e wszystkie zasoby nale| do odpowiednich obiektów. Zasoby przy- dzielane dynamicznie najlepiej przechowywa za po[rednictwem wskazników  inteli- gentnych , a nie zwykBych. Warto te| ka|dy jawny przydziaB zasobu (np. wywoBanie operatora ) wyodrbnia do osobnej instrukcji, w której nowo przydzielony zasób natychmiast wdruje pod opiek swojego dysponenta (np. wskaznika ); inaczej Batwo o wycieki zasobów spowodowane nieoczekiwanym porzdkiem ewaluacji parametrów funkcji (porzdek ten jest bowiem niezdefiniowany  patrz wytyczna 31.). Oto przykBad: Powy|szy kod nie jest bezpieczny. Standard jzyka C++ daje twórcom kompilatorów znaczn swobod w zakresie porzdkowania wyra|eD reprezentujcych argumenty wywoBania funkcji. W szczególno[ci kompilator mo|e przeplata obliczanie obu wyra- |eD i najpierw wykona przydziaB pamici dla obu obiektów (operatorem ), a potem dopiero wywoBa (w dowolnej kolejno[ci) konstruktory obiektów klasy . W takim ukBadzie bardzo Batwo o wyciek pamici, poniewa| je[li jeden z konstruktorów zgBosi wyjtek, to pami drugiego z obiektów nie zostanie nigdy zwolniona (po szczegóBy odsyBamy do [Sutter02])! Ten subtelny problem ma proste rozwizanie: wystarczy pilnowa, aby w pojedynczej instrukcji nie przydziela wicej ni| jednego zasobu, a ka|dy przydziaB realizowa jawnie, z natychmiastowym przekazaniem zasobu do obiektu-dysponenta (np. wskaz- nika ). Jak tutaj: Wytyczna 13. Zagwarant j opiek nad zasobami przez obiekty. Stos j RAII& 51 Inne zalety stosowanie takiej konwencji przedstawione zostan w wytycznej nr 31. Wyjtki Latwo o nadu|ycie inteligentnych wskazników. ZwykBe wskazniki [wietnie sprawdzaj si w kodzie, w którym wskazywane zasoby s widoczne jedynie w ograniczonym frag- mencie kodu (np. wyBcznie wewntrz klasy, jak w przypadku wewntrznych wskazni- ków nawigacji w[ród wzBów w klasie ). yródBa [Alexandrescu00c] [Cline99] §31.03 05 [Dewhurst03] §24, §67 [Meyers96] §9 10 [Milewski01] [Stroustrup00] § 14.3 4, §25.7, §E.3, §E.6 [Sutter00] §16 [Sutter02] §20 21 [Vandervoorde03] §20.1.4

Wyszukiwarka

Podobne podstrony:
Wytyczne do praktyk pedagogicznych
standard kodowania 07 07 17
wytyczne do standar przyl4
9 Wytyczne do przeprowadzania raportów z inspekcji spełnienia zasad DPL
18 praktycznych zasad fotografii cyfrowej
Miedzynarodowe Standardy Rachunkowosci Praktyczne zastosowanie w biznesie mistra
Skrócony zbiór zasad dobrej praktyki rolniczej dla potrzeb wdrażania Dyrektywy Azotanowej(1)
WytyczneTBD Czesc4 Standardy wymiany?nych ver1
Amator też człowiek, czyli 18 praktycznych zasad fotografii cyfrowej

więcej podobnych podstron