Pytanie: Dlaczego Java / C # nie może implementować RAII?
Wyjaśnienie: Wiem, że śmieciarz nie jest deterministyczny. Dlatego przy obecnych funkcjach językowych nie jest możliwe automatyczne wywoływanie metody Dispose () obiektu przy wyjściu z zakresu. Ale czy można dodać taką cechę deterministyczną?
Moje zrozumienie:
Wydaje mi się, że implementacja RAII musi spełniać dwa wymagania: 1. Żywotność zasobu musi być związana z zakresem.
2. Implikowany. Zwolnienie zasobu musi nastąpić bez wyraźnego oświadczenia programisty. Analogicznie do śmieciarza zwalniającego pamięć bez wyraźnego oświadczenia. „Ujawnienie” musi wystąpić tylko w momencie użycia klasy. Twórca biblioteki klas musi oczywiście jawnie zaimplementować metodę destructor lub Dispose ().
Java / C # spełnia punkt 1. W C # zasób implementujący IDisposable może być powiązany z zakresem „using”:
void test()
{
using(Resource r = new Resource())
{
r.foo();
}//resource released on scope exit
}
Nie spełnia to punktu 2. Programista musi jawnie powiązać obiekt ze specjalnym zakresem „używającym”. Programiści mogą (i robią) zapomnieć o jawnym powiązaniu zasobu z zakresem, tworząc wyciek.
W rzeczywistości bloki „using” są konwertowane przez kompilator na kod try-ultimate-dispose (). Ma tę samą wyraźną naturę wzorca try-last-dispose (). Bez domniemanego zwolnienia hakiem do zakresu jest cukier składniowy.
void test()
{
//Programmer forgot (or was not aware of the need) to explicitly
//bind Resource to a scope.
Resource r = new Resource();
r.foo();
}//resource leaked!!!
Myślę, że warto utworzyć funkcję języka w Javie / C #, która pozwala na specjalne obiekty, które są zaczepiane do stosu za pomocą inteligentnego wskaźnika. Ta funkcja umożliwia oznaczenie klasy jako związanej z zakresem, dzięki czemu zawsze jest tworzona z zaczepem do stosu. Mogą istnieć opcje dla różnych rodzajów inteligentnych wskaźników.
class Resource - ScopeBound
{
/* class details */
void Dispose()
{
//free resource
}
}
void test()
{
//class Resource was flagged as ScopeBound so the tie to the stack is implicit.
Resource r = new Resource(); //r is a smart-pointer
r.foo();
}//resource released on scope exit.
Myślę, że domniemanie jest „tego warte”. Podobnie jak niejawność zbierania śmieci jest „tego warta”. Jawne używanie bloków odświeża oczy, ale nie zapewnia przewagi semantycznej nad try-last-dispose ().
Czy zaimplementowanie takiej funkcji w językach Java / C # jest niepraktyczne? Czy można to wprowadzić bez zerwania starego kodu?
using
wykonania Dispose
jest gwarantowane (cóż, pomijanie procesu nagle umiera bez wyjątku, w którym to momencie przypuszczalnie wszystkie porządki stają się dyskusyjne).
struct
), ale są one zazwyczaj unika z wyjątkiem bardzo szczególnych przypadkach. Zobacz także .
Dispose
s są zawsze uruchamiane, niezależnie od tego, jak są one wyzwalane. Dodanie ukrytego zniszczenia na końcu zakresu nie pomoże.