RAII-skie kwiatki

2008-04-11 19:43

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.:

  1. {
  2.    ThreadLock lock;
  3.    // (wykonywany tylko przez jeden wątek)
  4. }

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:

  1. ThreadLock lock();

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ę:

  1. ThreadLock (&mutex);

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.

Tags: , ,
Author: Xion, posted under Programming »


13 comments for post “RAII-skie kwiatki”.
  1. Cranegger:
    April 11th, 2008 o 21:17

    Ach te uroki C++ ;)
    Szkoda mi Was chłopaki (programiści tego języka)…

  2. SirMike:
    April 11th, 2008 o 22:01

    @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.

  3. Cranegger:
    April 12th, 2008 o 9:01

    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?

  4. krajek:
    April 12th, 2008 o 13:31

    ‘Co twórcy widzą złego w tej konstrukcji?’
    Cranegger w c++ jest ona zbędna – ni mniej, ni wiecej.

  5. SirMike:
    April 12th, 2008 o 18:08

    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.

  6. Cranegger:
    April 12th, 2008 o 18:48

    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++.

  7. Xion:
    April 12th, 2008 o 19:43

    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.

  8. yarpen:
    April 13th, 2008 o 19:47

    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.

  9. noisy:
    April 13th, 2008 o 23:02

    Poczekajcie na C++0x :P

  10. krajek:
    April 13th, 2008 o 23:33

    noisy no wlaśnie, ile można czekać :D.

  11. monika:
    January 3rd, 2011 o 14:18

    Co do samego C++. Ja zaczynałam naukę z Pascalem i dzięki temu coś mi wpadło do tej głowy:P.

Comments are disabled.
 


© 2017 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.