2

現在、次のようにマップの値の参照カウントキャッシュを実装しています。

//filename or name of bitmap, reference count, memory location...
std::map<std::string, std::pair<long, BITMAP*> > _cache;

std :: multimapを使用する方が良い選択ですか?

//filename or name of bitmap, memory location...
std::multimap<std::string, BITMAP*> _cache;

それとも別のやり方ですか?

- 編集 -

これが私の意図を明確にするための特定のクラスです。これは、ユーザーには決して表示されない残りのコードに対して厳密にユーティリティであるプライベートクラスであることが意図されています。彼らにとって、彼らはただスプライトを作成しているだけです。注:構造体はプライベートと見なされ、BITMAP構造体を作成/破棄/変更する唯一の方法は、生のポインターの使用を必要とするサードパーティのCライブラリにある多くの関数の1つを使用することです。

BitmapCache.h

#ifndef A2DE_CBITMAPCACHE_H
#define A2DE_CBITMAPCACHE_H

#include "../a2de_vals.h"
#include <allegro/file.h>
#include <allegro/gfx.h>
#include <allegro/draw.h>
#include <allegro/datafile.h>
#include <allegro/color.h>

#include <map>
#include <utility>
#include <string>

struct BITMAP;

_A2DE_BEGIN

class BitmapCache {
public:
    static BITMAP* GetBitmap(std::string filename);
    static BITMAP* StoreBitmap(std::string name, BITMAP* bmp);
    static BITMAP* RetrieveBitmap(std::string name);
    static std::string GetBitmapName(BITMAP* file);
    static void RemoveBitmap(std::string name);

protected:
private:
    static std::map<std::string, std::pair<long, BITMAP*> > _cache;
    static void CleanCache();

};

_A2DE_END

#endif

BitmapCache.cpp

#include "CBitmapCache.h"

#include <algorithm>
#include <map>

_A2DE_BEGIN

//filename or name of bitmap, reference count, memory location...
typedef std::map<std::string, std::pair<long, BITMAP*> > MapStrBmp;
typedef MapStrBmp::iterator MapStrBmpIter;

MapStrBmp BitmapCache::_cache;

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]);

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

    //Search for requested BITMAP.
    MapStrBmpIter _iter = _cache.find(filename);

    //If found, return it.
    if(_iter != _cache.end()) {
        _iter->second.first++;
        return _iter->second.second;
    }

    //Otherwise, create it, store it, then return it.
    BITMAP* result = load_bmp(filename.c_str(), NULL);
    if(result == NULL) return NULL;
    _cache.insert(std::make_pair(filename, std::make_pair(static_cast<long>(1), result)));
    return result;
}

BITMAP* BitmapCache::StoreBitmap(std::string name, BITMAP* bmp) {
    if(name.empty() || bmp == NULL) return NULL;

    CleanCache();
    name = fix_filename_slashes(&name[0]);
    MapStrBmpIter _iter = _cache.find(name);
    if(_iter != _cache.end()) {
        _iter->second.first++;
        return _iter->second.second;
    }

    _cache.insert(std::make_pair(name, std::make_pair(static_cast<long>(1), bmp)));
    return bmp;
}
BITMAP* BitmapCache::RetrieveBitmap(std::string name) {
    if(name.empty()) return NULL;

    name = fix_filename_slashes(&name[0]);
    MapStrBmpIter _iter = _cache.find(name);
    if(_iter != _cache.end()) {
        _iter->second.first++;
        return _iter->second.second;
    }
    return NULL;
}

void BitmapCache::RemoveBitmap(std::string name) {
    if(name.empty()) return;

    name = fix_filename_slashes(&name[0]);
    MapStrBmpIter _iter = _cache.find(name);

    if(_iter != _cache.end()) {
        _iter->second.first--;
        CleanCache();
    }
}

std::string BitmapCache::GetBitmapName(BITMAP* file) {
    if(file == NULL) return std::string("");

    CleanCache();
    MapStrBmpIter b = _cache.begin();
    MapStrBmpIter e = _cache.end();
    for(MapStrBmpIter _iter = b; _iter != e; ++_iter) {
        if(_iter->second.second != file) continue;
        return _iter->first;
    }
    return std::string("");
}

void BitmapCache::CleanCache() {

    //Clean the cache of any bitmaps that are no longer referenced.
    MapStrBmpIter b = _cache.begin();
    MapStrBmpIter e = _cache.end();
    for(MapStrBmpIter _iter = b; _iter != e; /* DO NOTHING */ ) {
        if(_iter->second.first > 0) {
            ++_iter;
            continue;
        }
        destroy_bitmap(_iter->second.second);
        _iter->second.second = NULL;
        _cache.erase(_iter++);
    }
}

_A2DE_END
4

3 に答える 3

4
std::map<std::string, std::pair<long, BITMAP*> > _cache;

車輪の再発明をしないでください。shared_ptr(特定のコンパイラのboostまたはtr1名前空間または新しいコンパイラのstd ::名前空間で使用可能)またはその他の十分にテストされたスマートポインタクラスを使用します。車輪の再発明は、プログラミングのよくある間違いの1つです。何か(他の誰かがすでに書いたもの)を再実装しようとすると、開発時間を無駄にし、何も得られません。

- 編集 -

およびdestroy_bitmapメソッド

boost::shared_ptrはカスタム削除機能をサポートしています。それらを使用してください。

同じファイル名が渡されたときに複数のBITMAPが作成されないようにするにはどうすればよいですか?

std::map<std::string, boost::weak_ptr<BITMAP> >。値がマップに存在しない場合、または既存のweak_ptrの有効期限が切れている場合は、deleterを使用して新しいshared_ptrを作成し、weak_ptrをマップに配置してこのshared_ptrを返します。それ以外の場合(weak_ptrは期限切れになっていない)、weak_ptrからshared_ptrを抽出し、それを返します。

もちろん、それは使用パターンに依存します。ある種の「リソースキャッシュ/プール」を記述していない場合(未使用のリソースはマップ内にある場合でも削除されます)、マップ内の削除機能で使用できますshared_ptr

于 2012-04-05T04:10:48.473 に答える
0

あなたが持っていると仮定します:

struct BITMAP;
BITMAP* create_bitmap(std::string const& filename);
void destroy_bitmap(BITMAP*);

次に、次のことができます。

typedef std::shared_ptr<BITMAP> bitmap_ptr;

class bitmap_cache {
public:
    bitmap_ptr
    make(std::string const& filename)
    {
        auto it = map.find(filename);
        if(it != map.end()) {
            return it->second;
        } else {
            bitmap_ptr p(create_bitmap(filename), &destroy_bitmap);
            map.insert(std::make_pair(filename, p));
            return p;
        }
    }

private:
    std::map<std::string, bitmap_ptr> map;
};

それぞれが作成されたすべての を存続期間中bitmap_cache維持しますが、未使用の はキャッシュが存続期間の終わりに達すると適切に破棄されることに注意してください (キャッシュの一部のクライアントによって使用されている は安全に存続します)。必要に応じて、代わりにマップ内で使用することで改善できます。BITMAPBITMAPBITMAPstd::weak_ptr<BITMAP>

于 2012-04-05T05:40:04.070 に答える
0

さて、私がやろうとしていることにSTLスマートポインターを使用できないことがわかりました。スマート ポインターを使用するように上記のコードを作り直した後、プログラムを閉じるとクラッシュし続けました。allegro 4.2 ライブラリ API は、allegro が初期化解除された後に allegro メソッド (具体的にはビットマップを扱うもの...) を呼び出そうとすると、プログラムがクラッシュすることを具体的に述べていることが判明しました。スマート ポインターは、スコープを使い果たした後、つまり、プログラムが終了して allegro が初期化解除された後にのみ、自分自身を破棄します (そして、含まれているポインターの削除メソッドを呼び出そうとします)。これにより、プログラムがクラッシュします。

したがって、今のところ、参照カウントの独自の実装を展開する現在のソリューションが回避策です。

とにかくアドバイスと助けをありがとう。

于 2012-04-10T22:52:32.627 に答える