Как освободить статическую переменную-член в C ++? - PullRequest
5 голосов
/ 05 мая 2010

Кто-нибудь может объяснить, как освободить память статического члена Variable? В моем понимании это может быть освобождено, только если все экземпляры класса уничтожены. На данный момент я немного беспомощен ...

Код, объясняющий это:

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

Ответы [ 8 ]

12 голосов
/ 05 мая 2010

Сам указатель будет вокруг, пока программа не закроется. Однако на это указывает честная игра. Вы можете освободить это в любое время.

Если вас беспокоит утечка памяти, у вас есть несколько вариантов, которые я вижу:

  1. Просто дай течь. Вся память из программы будет освобождена, когда она выключится. Однако, если вам нужно больше, чем просто освобождение памяти (например, если вы хотите, чтобы деструктор работал), то это не очень хорошая идея.

  2. Имеет статическую переменную-член, которая отслеживает, сколько экземпляров класса было создано. Освободите память, когда она достигнет нуля, и перераспределите ее, если она снова превысит 0.

  3. Имеет функцию какого-то рода, которая запускается при завершении работы программы и беспокоится об освобождении памяти.

  4. Если можете, сделайте так, чтобы больше не было указателя. Если это не указатель, вам не о чем беспокоиться.

  5. Используйте умный указатель или auto_ptr. Таким образом, когда указатель будет уничтожен, память будет сохранена.

Лично я бы посоветовал 4, если можете, и 5, если не можете, но у вас есть несколько вариантов.

11 голосов
/ 05 мая 2010

Судя по звуку, вам вообще не нужен указатель. Фактически, так как это происходит из фабричной функции в библиотеке C, это на самом деле не первоклассный указатель C ++. Например, вы не можете безопасно delete it.

Настоящая проблема (если она есть) заключается в том, чтобы вызвать SDL_FreeSurface до ее выхода из программы.

Для этого требуется простой класс-обертка.

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;

Когда программа инициализируется, вызывается конструктор и читается файл. Когда программа завершается, вызывается деструктор и объект уничтожается.

3 голосов
/ 05 мая 2010

Статическая переменная-член в этом случае является указателем. Вы не можете освободить его, но вы можете освободить то, на что оно указывает:

SDL_FreeSurface(ball_image);

Затем вы можете установить ball_image на 0, чтобы зафиксировать факт, что у вас больше нет изображения.

он может быть освобожден, только если уничтожены все экземпляры класса

Если под "классом" вы подразумеваете ball, то нет. Статические члены ball продолжают существовать независимо от количества экземпляров ball. Единственный способ, которым статический член может быть уничтожен перед выходом из программы, - это сделать что-то (зависящее от реализации), например, выгрузить dll, которая содержит класс. Но в этом случае статический член является просто указателем, поэтому (1) его уничтожение просто уничтожит указатель, а не указатель, и (2) нет необходимости уничтожать указатель в любом случае, он не занимает значительных ресурсов.

1 голос
/ 05 мая 2010

Я согласен с ответом Джонатана М. Дэвиса, но другой вариант, который вы могли бы рассмотреть, - это извлечение ваших изображений и других ресурсов из ваших «доменных объектов» в класс ResourceManager или что-то в этом роде.

ResourceManager может быть статическим или основанным на экземплярах и обеспечивать логику для загрузки и удаления ресурсов, необходимых для остальной части нашего приложения.

Классы, нуждающиеся в ресурсах, могут просто хранить ссылку или указатель на менеджер глобальных ресурсов и запрашивать ресурсы у менеджера, а не управлять ими самостоятельно.

1 голос
/ 05 мая 2010

Статический член существует полностью независимо от всех экземпляров класса, членом которого он является. Вы можете удалить указатель в любой точке программы. Имеет ли это смысл семантически, это, конечно, еще одна проблема.

1 голос
/ 05 мая 2010

Если вам нужен статический член, указывающий на выделенную кучу память, я бы сделал член умным указателем.

0 голосов
/ 13 октября 2014

Работая с static variable, когда память выделяется динамически, лучше использовать smart_pointer или метод, при котором память очищается вручную.

Очистка памяти статических переменных в destructor не будет работать для случая ниже: Поскольку статические члены существуют как members of the clas s, а не как instance in each object of the class. Поэтому, если кто-то получит доступ к статической переменной с помощью :: и динамически выделит память, destructor не появится на снимке и память не будет удалена, так как объект не создан.

0 голосов
/ 16 декабря 2012

Статические переменные-члены не нужно удалять. Если у вас есть один в классе, это потому, что вы хотите использовать его в любое время в течение всей жизни программы. После завершения программы операционная система запрашивает общий объем памяти, выделенной ей, включая любое неиспользованное пространство памяти.

Конечно, если вы настаиваете на его удалении, вы можете создать специальный статический метод-член для этого и вызвать метод в нужной точке программы. Но я не рекомендую это никому, потому что это нарушает семантическую целостность статических переменных-членов, увеличивая таким образом сложность и вероятность возникновения проблем по мере роста программы.

...