Jako język nie posiadający słowa kluczowego finally
, C++ preferuje nieco inną metodę na radzenie sobie z nieprzewidzianymi “wyskokami” z funkcji i związaną z tym możliwością wycieku zasobów (resource leak). Ten inny sposób jest znany skądinąd jako RAII: Resource Acquisition Is Initialization i polega na związaniu z każdym użyciem zasobu jakiegoś obiektu lokalnego, np.:
Proste i całkiem wygodne, jeśli tylko posiadamy już (lub zechcemy napisać) odpowiednią klasę, która w konstruktorze pozyskuje dany zasób – tutaj blokadę muteksa – a w destruktorze go oddaje.
Ale ten nieskomplikowany mechanizm daje możliwości popełnienia błędów, które są na swój interesujące, ale w realnym kodzie na pewno niezbyt przyjemne :) Pierwszy z nich związany jest z faktem, że lokalnych obiektów nie tworzy się znowu aż tak dużo i można popełnić w ich składni drobne, acz wielce znaczące faux pas z nawiasami:
Taki wiersz nie stworzy nam bowiem żadnego obiektu, ale zadeklaruje funkcję lock
, zwracającą obiekt typu ThreadLock
i niebiorącą żadnych argumentów. Zaskakujące? A to tylko prosta konsekwencja faktu, że cokolwiek, co można zinterpretować w C++ jako deklarację funkcji, zostanie tak właśnie zinterpretowane.
Można jednak ripostować, że nic takiego nie zdarzy się, jeśli do konstruktora naszego obiektu-blokady przekażemy chociaż jeden parametr. A zwykle tak właśnie będzie; tutaj np. byłoby nim odwołanie do obiektu typu mutex lub semafora, który chcemy zająć. Jednak nie zmienia to faktu, że w większości przypadków obiekt realizujący RAII wystarcza nam przez samo swoje istnienie, co z kolei sprawia, że w dalszym kodzie w ogóle się do niego nie odwołujemy. To zaś może spowodować, że pominiemy i tak nieużywany składnik jego deklaracji – czyli nazwę:
Takie zagranie również nie powinno wywołać protestów kompilatora, ale prawie na pewno nie jest tym, o co nam chodzi. Tworzony obiekt jest teraz bowiem nie lokalny, ale tymczasowy: jego zasięg ogranicza się do wyrażenia, w którym został wprowadzony. Czyli do… średnika kończącego powyższą instrukcję! Taki też zakres ma opakowana przez ów obiekt blokada międzywątkowa.
Jak zatem widać, jest tu kilka okazji do popełnienia błędów, które mogą być trudne do wykrycia. Powinniśmy więc zwrócić na nie uwagę tym bardziej, że wobec braku w C++ instrukcji finally
technika RAII jest jedynym sensownym wyjściem dla lokalnego pozyskiwania i zwalniania zasobów.
Ach te uroki C++ ;)
Szkoda mi Was chłopaki (programiści tego języka)…
@Cranegger: Kazdy jezyk ma swoj urok. Zapewniam Cie, ze np. w C# jest tyle samo kretynizmow i niedorobek, z ktorymi trzeba sobie radzic. O nieintuicyjnych slowach kluczowych, jak np. readonly to juz nawet nie wspominam.
Co do C# się nie wypowiadam, bo prawie nic w nim nie pisałem ;) ale też mi się nie podoba to readonly. Ja siedzę w Javie…
C++ ma ich bardzo dużo – o czym świadczą ciągłe narzekania na przeróżnych blogach. O żadnym innym języku się tyle nie nasłuchałem…
Zabawne jest to, że w C++ nie ma słowa finally. Co twórcy widzą złego w tej konstrukcji?
‘Co twórcy widzą złego w tej konstrukcji?’
Cranegger w c++ jest ona zbędna – ni mniej, ni wiecej.
Jezyk C++ powstal na poczatku lat 80tych. Java ponad 10 lat pozniej, C# jeszcze pozniej. To, ze nie ma w C++ czegos co jest w mlodszych jezykach programowania jest chyba bardzo normalne, prawda?
Mechanizm wyjatków tez pojawil sie w tym jezyku stosunkowo dawno, jak dobrze pamietam byl to poczatek lat 90tych. Java ze swoim finally wtedy jeszcze nie istniala :P
Pomijajac juz cala historie, finally w C++ jest calkowicie zbedne. Tak samo jak cala plejada featuresow poczawszy od Garbage Collectora na wyrazeniach Lambda skoczywszy.
No chyba jednak nie jest zbędne, skoro powstają takie wpisy na blogu. Wiem, że C++ jest stary, ale przecież w którymś standardzie mogliby dodać finally.
Z wyjątkami to mnie zaskoczyłeś. Jakoś mi się wydawało, że były od początku w C++.
Zarówno wyjątków, jak i szablonów, nie było w C++ od początku.
Co do kwestii finally, to pragnę zaznaczyć, że w tym wpisie ani jednym słowem nie stwierdziłem, że brak tej instrukcji w C++ jest zły. Wskazałem tylko na kruczki związane z użyciem jej alternatywy, czyli RAII.
Ja bym sie za lambde w C++ nie obrazil. “Zbedne” tak naprawde jest 90% mechanizmow, ktore mamy w dzisiejszych jezykach, w koncu w assemblerze tez sie dalo fajne programy pisac.
Poczekajcie na C++0x :P
noisy no wlaśnie, ile można czekać :D.
Co do samego C++. Ja zaczynałam naukę z Pascalem i dzięki temu coś mi wpadło do tej głowy:P.