Статический член класса уничтожения в C++


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

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

Я должен создать инициализации и освободить методы строго новый и удалить СТД::МАП?

(Он назван бассейн в коде, потому что имя не обновлялось в этой публикации.)

BitmapCache.ч

#ifndef CBITMAPCACHE_H
#define CBITMAPCACHE_H

#include <allegro\file.h>
#include <allegro\gfx.h>
#include <allegro\draw.h>
#include <allegro\datafile.h>
#include <allegro\color.h>

#include <map>
#include <string>

struct BITMAP;

class BitmapCache {
public:

    static BITMAP* GetBitmap(std::string filename);
    static BITMAP* GetBitmap(BITMAP* file);
    static std::string GetBitmapFilename(BITMAP* file);
    static BITMAP* GetBlankBitmap(int width, int height);

protected:
private:

    static std::map<std::string, BITMAP*>* _pool;
    static void CleanCache();
};

#endif

BitmapCache.cpp

#include "CBitmapCache.h"

#include <algorithm>

std::map<std::string, BITMAP*>* BitmapCache::_pool = NULL;

BITMAP* BitmapCache::GetBitmap(std::string filename) {
    //Return NULL if a bad filename was passed.
    if(filename.empty()) return NULL;
    if(exists(filename.c_str()) == false) return NULL;

    //Reduce incorrect results by forcing slash equality.
    filename = fix_filename_slashes(&filename[0]);

    //Create pool on first use.
    if(_pool == NULL) _pool = new std::map<std::string, BITMAP*>();

    //Clean the pool if it's dirty.
    CleanCache();

    //Search for requested BITMAP.
    std::map<std::string, BITMAP*>::iterator _iter = _pool->find(filename);

    //If found, return it.
    if(_iter != _pool->end()) return _iter->second;

    //Otherwise, create it, store it, then return it.
    BITMAP* result = load_bmp(filename.c_str(), NULL);
    if(result == NULL) return NULL;
    _pool->insert(std::pair<std::string, BITMAP*>(filename, result));
    return result;
}

BITMAP* BitmapCache::GetBitmap(BITMAP* file) {
    if(file == NULL) return NULL;
    if(_pool == NULL) new std::map<std::string, BITMAP*>();

    CleanCache();

    for(std::map<std::string, BITMAP*>::iterator _iter = _pool->begin(); _iter != _pool->end(); ++_iter) {
        if(_iter->second != file) continue;
        return _iter->second;
    }
    return NULL;
}

std::string BitmapCache::GetBitmapFilename(BITMAP* file) {
    if(file == NULL) return std::string("");
    if(_pool == NULL) return std::string("");
    CleanCache();
    for(std::map<std::string, BITMAP*>::iterator _iter = _pool->begin(); _iter != _pool->end(); ++_iter) {
        if(_iter->second != file) continue;
        return _iter->first;
    }
    return std::string("");
}

BITMAP* BitmapCache::GetBlankBitmap(int width, int height) {

    //Smallest allowed size is 1x1.
    if(width < 1 || height < 1) return NULL;

    //Create pool on first use.
    if(_pool == NULL) _pool = new std::map<std::string, BITMAP*>();

    //Cleans the cache.
    CleanCache();

    //Partial Sequential Search for requested BITMAP.
    if(_pool->empty() == false) {
        for(std::map<std::string, BITMAP*>::iterator _iter = _pool->begin(); _iter != _pool->end(); ++_iter) {
            //String keys sorted in ascending order.
            //If key is not empty reached non-blank section.
            if(_iter->first.empty() == false) break;
            if(width == _iter->second->w && height == _iter->second->h) {
                return _iter->second;
            }
        }
    }
    //Attempt to create bitmap, if failed, return NULL.
    BITMAP* result = create_bitmap(width, height);
    if(result == NULL) return NULL;

    //Clear to black, store it, then return to caller.
    clear_bitmap(result);
    _pool->insert(std::pair<std::string, BITMAP*>("", result));
    return result;
}

void BitmapCache::CleanCache() {
    //Clean the pool of any NULL bitmaps that were deleted by caller.
    for(std::map<std::string, BITMAP*>::iterator _iter = _pool->begin(); _iter != _pool->end(); ++_iter) {
        if(_iter->second != NULL) continue;
        _pool->erase(_iter);
    }
}


1962
4
задан 16 августа 2011 в 07:08 Источник Поделиться
Комментарии
3 ответа

Аааа, чудесный мир игрового дизайна - я предполагаю, что это то, что вы делаете.
На мой взгляд, три наиболее распространенные решения (в порядке моего предпочтения):


  1. Сделать кэш объект, а не указатель на объект. Это
    так оно автоматически быть правильно уничтожены, когда ваш
    заканчивается заявление. Недостатки: нет реального способа, чтобы выключить игру и
    'перезагрузка' без перезапуска приложения, но если вы переключаетесь
    библиотеки или графических интерфейсов, это тоже не очень нужны.

  2. Оставить все как есть, не волнуйся. Я знаю, что деструктор не будет
    запускается, но при выходе из приложения операционной системы будут вернуть каждый бит
    в любом случае памяти. Однако, не делайте этого, если есть "важный"
    задачи, которые должны быть учтены в кэше уничтожения, как
    (я не знаю) что-то писать на диск. Обратите внимание, что это
    только жизнеспособным, если вы хотите сбросить весь объект кэша (не
    только ее содержимое) только по окончании процесса, иначе вы не
    будут серьезные утечки памяти. Также не делайте этого, если приложение должно продолжать работу в течение длительного времени после вашей игры ушел.

  3. В случае если ни 1) ни 2) являются жизнеспособными, вы, вероятно, в необходимости выключить игру вашему '
    двигатель и запустить его снова, не выключая приложения. В
    в этом случае, однако у вас будет в любом случае какой-то метод, чтобы закрыли
    переинициализации все'/'закрыть двигатель'/''/называйте как хотите. Тогда
    просто, этот метод может позаботиться об освобождении кэш.

Примечание к Решение 2: это 'решение' грязный, и если вы хороший кодер, вы действительно должны уничтожить все объекты даже при выходе из приложения, просто, как я всегда делаю. Но, честно говоря, в данном конкретном случае вы практически ничего не приобретет. Единственное, что я могу думать, это, если вы используете детектор утечки памяти, надлежащим образом прекратив все избавлю вас от тысяч ложных предупреждений (что важно при использовании течеискателя). Если вы не уверены, забыли про вариант 2) и сделать это правильно.

4
ответ дан 16 августа 2011 в 08:08 Источник Поделиться

Вы инициализация ленивая, поэтому нет необходимости для явной инициализации. В релизе способ будет одним из вариантов, чтобы очистить память после использования и установки бассейна в нуль снова. Я предполагаю, что ваш код предназначен для одного потока только поэтому нет никаких реальных проблем. Другим вариантом могло бы быть использование экземпляров вашей (тогда модифицированный) класс. Таким образом, вы дать пользователю контроль использовать разные кэши для разных целей. Кэш удаляет, если он выходит из области видимости (местное применение) или если пользователь явно не хочет.

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

Кстати, я бы предложил typedef для СТД::карта и с std::пара делает код немного более читаемым.

0
ответ дан 16 августа 2011 в 07:08 Источник Поделиться

Если я понимая, что ты делаешь правильно, кажется, что абоненты должны получить shared_ptr в растровое изображение, в то время как кэш хранит weak_ref. Этак, растровые изображения могут существовать только, пока вы используете их, и кэш будет знать, когда растровое изображение перестает быть использовано (в weak_ref становится недействительным). Однако, это приводит к издержки shared_ptr, которые могут быть недопустимы в игре.

Редактировать:

Я не уверен, почему вы хотели новые и удалять карты; однако, вы могли бы заставить людей выпуск() каждого отдельного растрового, и на карте будет потом проверить, что во время чистки. Это повлечет за собой очень мало накладных расходов (один типа bool, плюс чек и периодически удалять при поиске).

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

0
ответ дан 20 августа 2011 в 06:08 Источник Поделиться