2010-05-04 12 views
5

Czy ktoś może wyjaśnić, jak zwolnić pamięć elementu statycznego Zmienna? W moim rozumieniu można go uwolnić tylko wtedy, gdy wszystkie instancje klasy zostaną zniszczone. Jestem trochę bezradny w tym momencie ...Jak uwolnić statyczną zmienną składową w C++?

jakiś kod to wytłumaczyć:

class ball 
{ 
    private: 
    static SDL_Surface *ball_image; 
}; 
//FIXME: how to free static Variable? 
SDL_Surface* ball::ball_image = SDL_LoadBMP("ball.bmp"); 

Odpowiedz

11

Z tego dźwięku nie potrzebujesz wcale wskaźnika. W rzeczywistości, ponieważ pochodzi on z funkcji fabrycznej w bibliotece C, nie jest tak naprawdę "wskaźnikiem C++ pierwszej klasy". Na przykład nie można go bezpiecznie delete.

Prawdziwym problemem (jeśli taki występuje) jest wywołanie na nim SDL_FreeSurface przed wyjściem programu.

Wymaga to prostej klasy opakowania.

struct smart_sdl_surface { 
    SDL_Surface *handle; 

    explicit smart_sdl_surface(char const *name) 
     : handle(SDL_LoadBMP(name)) {} 
    ~smart_sdl_surface() 
     { SDL_FreeSurface(handle); } 
}; 

class ball 
{ 
    private: 
    static smart_sdl_surface ball_image_wrapper; 
    static SDL_Surface *& ball_image; // reference to the ptr inside wrapper 
}; 
smart_sdl_surface ball::ball_image_wrapper("ball.bmp"); 
SDL_Surface *&ball::ball_image = ball::ball_image_wrapper.handle; 

Podczas inicjowania programu konstruktor jest wywoływany, a plik jest odczytywany. Po wyjściu programu destruktor jest wywoływany, a obiekt jest niszczony.

12

Wskaźnik sama będzie wokół aż program zostanie zamknięty. Jednak wskazuje na uczciwą grę. Możesz to uwolnić w dowolnym momencie.

Jeśli martwisz się o to wycieki pamięci, a następnie masz kilka opcji, które widzę:

  1. Daj mu przeciekać. Cała pamięć programu zostanie zwolniona po wyłączeniu. Jednakże, jeśli potrzebujesz czegoś więcej niż tylko uwolnionej pamięci (jak chcesz uruchomić destruktor), to nie jest taki dobry pomysł.

  2. Mieć statyczną zmienną składową, która śledzi liczbę instancji klasy. Zwolnij pamięć, gdy osiągnie zero i dokonaj jej ponownego przydzielenia, jeśli przekroczy ona ponownie 0.

  3. Mieć jakąś funkcję, która działa, gdy program jest zamykany i martwić się o zwolnienie pamięci.

  4. Jeśli możesz, spraw, aby nie był już wskaźnikiem. Jeśli nie jest wskaźnikiem, nie musisz się tym martwić.

  5. Użyj numeru smart pointer lub auto_ptr. W ten sposób, gdy sam wskaźnik zostanie zniszczony, pamięć zostanie zajęta.

Osobiście, radziłbym 4, jeśli możesz i 5, jeśli nie możesz, ale masz kilka opcji.

+0

Usunięto moją odpowiedź, która była podobna do twojej, ale nie tak dokładna. – Nate

+0

Mój pomysł polegał na zrobieniu tego tak, jak opisałeś w 2., ale myślałem, że może być lepszy sposób. Co to jest inteligentny wskaźnik? Nigdy wcześniej o tym nie słyszałem. Brzmi jak odśmiecanie. – user299831

+0

Inteligentny wskaźnik to obiekt, który posiada wskaźnik, pozwala na użycie go tak, jakby był wskaźnikiem i zwalnia tę pamięć dla wskaźnika, gdy jest zniszczony (często robi się to poprzez liczenie odniesień, aby zobaczyć, czy istnieje są jakiekolwiek odniesienia do wskaźnika). Jest podobny do usuwania śmieci, ponieważ zarządza pamięcią dla ciebie, ale jest to oddzielna koncepcja. Dodałem link do implementacji boost. Jest na nich mnóstwo informacji - w tym na wikipedii. Ponadto, jeśli po prostu przeszukujesz inteligentne wskaźniki w SO, otrzymasz szereg pytań z nimi związanych. –

3

Statyczna zmienna składowa w tym przypadku jest wskaźnikiem. Nie można go zwolnić, ale można zwolnić, co wskazuje na:

SDL_FreeSurface(ball_image); 

Można wtedy chcesz ustawić ball_image 0, do zarejestrowania faktu, że nie masz już obraz.

może być zwolniona tylko wtedy, gdy wszystkie instancje klasy są niszczone

Jeśli przez „klasa” znaczy ball, to nie. Członkowie statyczni ball nadal istnieją niezależnie od tego, ile wystąpiło w nich instancji ball. Jedynym sposobem, w jaki statyczny element członkowski może zostać zniszczony przed zakończeniem programu, jest wykonanie pewnych czynności (zależnych od implementacji), takich jak rozładowanie biblioteki DLL zawierającej tę klasę. Ale w tym przypadku element statyczny jest tylko wskaźnikiem, więc (1) jego zniszczenie spowoduje tylko zniszczenie wskaźnika, a nie pointee, i (2) nie ma potrzeby, aby i tak zniszczyć wskaźnik, nie zajmuje on znacznych zasobów.

1

Jeśli konieczne jest, aby element statyczny wskazywał pamięć przydzieloną stertom, uczyniłbym element członkowski inteligentnym wskaźnikiem.

1

Statyczny element członkowski istnieje całkowicie niezależnie od wszystkich wystąpień klasy, której jest członkiem. Możesz usunąć wskaźnik w dowolnym punkcie programu. Czy to ma sens semantycznie, to oczywiście inna sprawa.

1

Zgadzam się z odpowiedzią Jonathana M Davisa, ale inną opcją, którą można rozważyć, jest wyciąganie obrazów i innych zasobów z "obiektów domeny" do klasy ResourceManager lub czegoś podobnego.

Program ResourceManager może być statyczny lub oparty na instancjach i zapewniałby logikę do ładowania i usuwania zasobów wymaganych przez resztę naszej aplikacji.

Klasy wymagające zasobów mogą po prostu zawierać referencję lub wskaźnik do globalnego menedżera zasobów i żądać zasobów od menedżera, zamiast zarządzać nimi samodzielnie.

0

Statyczne zmienne składowe nie muszą być usuwane. Jeśli masz go w klasie, to dlatego, że chcesz go używać w dowolnym momencie w trakcie całego życia programu. Po zakończeniu programu system operacyjny odrzuca całą przydzieloną mu pamięć, w tym wszelkie niewykorzystane miejsce w pamięci.

Oczywiście, jeśli nalegasz na jego usunięcie, możesz utworzyć specjalną metodę statycznego elementu, aby to zrobić i wywołać metodę w pożądanym miejscu w programie. Ale nie polecam tego nikomu, ponieważ narusza semantyczną integralność statycznych zmiennych składowych, zwiększając złożoność i prawdopodobieństwo powodowania problemów w miarę rozwoju programu.

0

Pracując z static variable, gdzie pamięć jest przydzielana dynamicznie, lepiej jest przejść z smart_pointer lub metodą, w której pamięć jest usuwana ręcznie.

Wyczyszczenie pamięci varibles statycznych w destructor nie będzie działać na poniższym przypadku: członkowie jako statyczne istnieć jako members of the clas s zamiast jako instance in each object of the class. Jeśli więc ktoś uzyska dostęp do zmiennej statycznej za pomocą :: i dynamicznie przydzieli pamięć, destructor nie pojawi się na obrazie, a pamięć nie zostanie usunięta, ponieważ nie utworzono żadnego obiektu.

Powiązane problemy