Co to jest RAII? Przykłady?


19

Zawsze, gdy używa się terminu RAII, ludzie faktycznie mówią o dekonstrukcji zamiast inicjalizacji. Myślę, że mam podstawową wiedzę na temat tego, co to może oznaczać, ale nie jestem całkiem pewien. Też: C ++ jest jedynym językiem RAII? Co o Java lub C # /. NET?

Odpowiedzi:


25

Pozyskiwanie zasobów to inicjalizacja oznacza, że ​​obiekty powinny dbać o siebie jako kompletny pakiet i nie oczekiwać, że inny kod powie instancji: „hej, zaraz zostaniesz oczyszczony - proszę posprzątaj teraz”. To nie znaczy, że zwykle jest czymś znaczącym w destructor. Oznacza to również napisać klasę specjalnie do zarządzania zasobami, wiedząc, że w pewnych trudnych do przewidzenia okoliczności, jak wyjątki wyrzucane, można liczyć na destruktorów wykonawczych.

Powiedzmy, że chcesz napisać kod gdzie masz zamiar zmienić okna kursor do wait (klepsydra, pączek-of-nie-pracy, itp) kursor, zrobić swoje rzeczy, a następnie zmienić go z powrotem. I powiedzieć, że „robić swoje rzeczy” może rzucić wyjątek. Sposób RAII robi, że byłoby zrobić klasę, której konstruktor ustawić kursor czekać, którego jeden „prawdziwy” sposób zrobił cokolwiek to chciałeś zrobić, a którego dtor ustawić tył kursora. Środki (w tym przypadku stan kursor) są związane z zakresu przedmiotu. Kiedy nabyć zasób zainicjować obiekt. Możesz liczyć na zniszczenie obiektu, jeśli zostaną zgłoszone wyjątki, a to oznacza, że ​​możesz liczyć na oczyszczenie zasobu.

Korzystanie RAII również oznacza, że nie trzeba finally. Oczywiście, to zależy od deterministycznego zniszczenia, które nie można mieć w Javie. Można dostać rodzaju deterministycznej destrukcji w C # i VB.NET z using.


4
Myślę, że o to ci chodzi, ale możesz dodać, że powodem, dla którego Java i C # nie obsługują RAII, jest z powodu śmieciarza. W C ++, lokalny obiekt zostanie zniszczony tak szybko jak to jest poza zakresem. W Java / C # nie jest to prawdą.
Jason Baker

Rozwijając punkt Jasons, powodem, dla którego Java i C # nie mogą zagwarantować terminowego zniszczenia, jest możliwość cykli odniesienia, co oznacza, że ​​nie można ustalić bezpiecznego porządku uruchamiania niszczycieli. Cykle referencyjne mogą się również zdarzyć w C ++, ale implikacje są różne - programista staje się odpowiedzialny za określenie kolejności niszczenia i wyraźne usuwanie. Odpowiedzialność ta bardzo często spoczywa w niszczycielach klas wyższego poziomu - np. Klasa kontenerów jest odpowiedzialna za zniszczenie wszystkich zawartych w niej przedmiotów. „Własność” jest kluczem.
Steve314,

1
@Jason to właśnie miałem na myśli przez „deterministycznej destrukcji” - programista C ++ nie wie, kiedy destruktor zostanie uruchomiony.
Kate Gregory

Wiem, że to stary odpowiedź, ale mam jeszcze trochę zdezorientowany. Właśnie dowiedziałem się od terminu i kilka informacji mówi, że nabycie powinno się zdarzyć w konstruktorze. Że tak naprawdę nie ma dla mnie sensu i ta odpowiedź wydaje się to sprzeczne, ale można wyjaśnić?
Per Johansson

1
@PerJohansson Tak, można nabyć w ctor. I uwalniasz w dtor. Byłem koncentrując się na drugim miejscu, ale idą razem. Gdy konstruktor odbywa wiesz, że masz ważny obiekt. I wiesz, że bez względu na to, co się dzieje, zasób zostanie wydany w odpowiednim czasie.
Kate Gregory

4

RAII częściowo polega na decydowaniu, kiedy obiekt staje się odpowiedzialny za swoje własne czyszczenie - reguła jest taka, że ​​obiekt staje się odpowiedzialny, jeśli i kiedy inicjalizacja konstruktora zakończy się. Symetria inicjalizacji i czyszczenia, konstruktor i destruktor, oznaczają, że oba są ze sobą ściśle powiązane.

Jednym z punktów RAII jest zapewnienie bezpieczeństwa wyjątków - aplikacja zachowuje spójność w przypadku zgłaszania wyjątków. Na pierwszy rzut oka jest to trywialne - gdy wyjątek powoduje zamknięcie zakresu, lokalne zmienne w tym zakresie muszą zostać zniszczone.

Ale co się stanie, jeśli rzut wyjątek występuje w konstruktorze?

Cóż, obiekt nie został w pełni zbudowany, więc nie można go bezpiecznie zniszczyć. Konstruktor powinien w razie potrzeby wypróbować bloki, aby zapewnić, że wszystkie niezbędne czyszczenia zostaną wykonane przed zgłoszeniem wyjątku. Gdy wyjątek stanie się spoza zakresu, w którym obiekt został skonstruowany, nie będzie wywołania destruktora, ponieważ obiekt nie został skonstruowany w pierwszej kolejności.

Rozważmy w szczególności konstruktorzy dla danych państw wewnątrz obiektu jest utylizowany. Jeśli jeden z tych, zgłasza wyjątek, Twój kod główny konstruktor nie będzie działać w ogóle - ale niektóre kod, który tworzy niejawny część tego konstruktora będzie miał. Wszelkie członków, które zostały pomyślnie wykonane zostaną automatycznie zniszczone. Każdy członek, które nie zostały wytworzone (włącznie z tym, który zwrócił wyjątek) nie.

Zasadniczo RAII to zasada, która gwarantuje, że wszystko, co zostanie w pełni zbudowane, zostanie zniszczone w odpowiednim czasie, szczególnie w przypadku wyjątków, i że każdy obiekt albo zostanie w pełni skonstruowany, albo nie jest (nie ma połowy zbudowane obiekty, które nie może wiedzieć, jak bezpiecznie oczyścić). Zasobów, które są przydzielane są również uwolniony. I dużo pracy jest zautomatyzowany, więc programista nie musi martwić się zbytnio o niego.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.