C ++:std :: map中的引用计数值; std :: multimap是更好的选择吗?

时间:2012-04-05 04:00:38

标签: c++ multimap stdmap reference-counting

目前我已经实现了地图值的引用计数缓存,如下所示:

//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库中的许多函数之一 REQUIRE < / em>使用原始指针。

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

3 个答案:

答案 0 :(得分:4)

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

不要重新发明轮子。使用shared_ptr(在某些编译器中的boost或tr1命名空间中或新编译器中的std :: namespace中)或任何其他现有的经过良好测试的智能指针类。重新发明轮子是常见的编程错误之一 - 通过尝试重新实现某些东西(已经由其他人编写过),你将浪费开发时间并获得任何收益。

- 编辑 -

  

和destroy_bitmap方法

boost :: shared_ptr支持自定义删除。使用它们。

  

如何在

中传递相同的文件名时创建几个BITMAP

std::map<std::string, boost::weak_ptr<BITMAP> >。如果map中不存在value,或者现有的weak_ptr已过期,则使用deleter创建新的shared_ptr并将weak_ptr放入map并返回此shared_ptr。否则(weak_ptr尚未过期)从weak_ptr中提取shared_ptr并返回它。

当然,这取决于使用模式。如果您没有编写某种“资源缓存/池”(即使它们位于地图中,也会删除未使用的资源),那么您可以将shared_ptr与地图中的删除者一起使用。

答案 1 :(得分: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在其生命周期内保持所有已创建的BITMAP处于活动状态,但当缓存达到其生命周期结束时,未使用的BITMAP将被正确处理掉(缓存的某个客户端正在使用的BITMAP将保持安全存活状态。如果您需要,可以在地图中使用std::weak_ptr<BITMAP>进行改进。

答案 2 :(得分:0)

嗯,事实证明我不能将STL智能指针用于我想做的事情。在重新处理上面的代码以使用智能指针之后,程序一直在崩溃。事实证明,allegro 4.2库API明确指出,在allegro被取消初始化后尝试调用allegro方法(特别是处理位图的方法......)会使程序崩溃。智能指针只会在程序结束后删除自身(并尝试调用其包含的指针的删除方法)...程序结束后并且allegro已被取消初始化,从而导致程序崩溃。

所以现在,滚动我自己的引用计数实现的当前解决方案是解决方法。

感谢您的建议和帮助。