目前我已经实现了地图值的引用计数缓存,如下所示:
//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
答案 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已被取消初始化,从而导致程序崩溃。
所以现在,滚动我自己的引用计数实现的当前解决方案是解决方法。
感谢您的建议和帮助。