参照カウンタ付きのキャッシュ
大雑把に実装してみた。
もっと抽象化できると思う。
まずは、main.cpp
// main.cpp #include<iostream> #include "CacheManager.h" using namespace std; // シングルトンお試し用 void init(); void run(); void end(); void disp(int num, InterfaceResource **ress) { for(int i=0; i<num; ++i) { if(ress[i]) cout << "+ " << i << " : " << ress[i]->getName() << ", " << ress[i] << endl; else cout << "+ " << i << " : " << ress[i] << endl; } } int main() { #define cm CacheManager::GetInstance() init(); run(); end(); return 0; } void init() { cm->init(); } void run() { InterfaceResource* res[8]; cout << "-------------- init" << endl; cm->dispCache(); // リソース取得 string name[5] = { "aaa", "bbb", "ccc", "ddd", "eee" }; for(int i=0; i<8; ++i) res[i] = cm->getRes(name[i%4]); cout << "-------------- after get Resources" << endl; cm->dispCache(); disp(8, res); // res[2]とres[6]を開放 cm->releaseRes(res[2]); cm->releaseRes(res[6]); cout << "-------------- after release index 2 and 6" << endl; cm->dispCache(); disp(8, res); // res[2]に別リソース取得 res[2] = cm->getRes(name[4]); cout << "-------------- after res[2] get other Resource" << endl; cm->dispCache(); disp(8, res); // res[0]からres[3]まで開放 for(int i=0; i<4; ++i) cm->releaseRes(res[i]); cout << "-------------- after release some Resources" << endl; cm->dispCache(); disp(8, res); // 全部開放 for(int i=0; i<8; ++i) cm->releaseRes(res[i]); cout << "-------------- after release all Resources" << endl; cm->dispCache(); disp(8, res); } void end() { cm->init(); }
キャッシュの内容と、リソース取得用配列の内容を表示。
+ が付いているのが後者。
リソースのインターフェイス。
こいつで操作。
本題ではないので簡素。
// InterfaceResource.h #ifndef __InterfaceResource__ #define __InterfaceResource__ #include <string> using namespace std; class InterfaceResource { public: virtual ~InterfaceResource() {} virtual void showName() = 0; virtual string getName() = 0; }; #endif // __InterfaceResource__
// Resource.h #ifndef __Resource__ #define __Resource__ #include "InterfaceResource.h" #include <iostream> #include <string> using namespace std; class Resource : public InterfaceResource { public: Resource(string name); virtual ~Resource() { } void showName(); string getName(); private: string m_name; }; #endif // __Resource__
// Resource.cpp #include "Resource.h" Resource::Resource(string name) : m_name(name) { } void Resource::showName() { cout << m_name << endl; } string Resource::getName() { return m_name; }
キャッシュ経由でリソースの取得と開放を行う。
// CacheManager.h #ifndef __CacheManager__ #define __CacheManager__ #include "InterfaceResource.h" // キャッシュと参照カウンタ struct Cache { int RefCount; string Name; // IDの代わり(Resourceを識別するものを使う) InterfaceResource* resource; }; // キャッシュと参照カウンタを管理 class CacheManager { enum{ CACHE_MAX=8 }; public: InterfaceResource* getRes(string name); void releaseRes(InterfaceResource* (&res)); // ポインタを参照渡し void dispCache(); void init(); private: Cache m_cache[CACHE_MAX]; // シングルトン public: // 唯一のアクセス static CacheManager* GetInstance() { static CacheManager instance; // 唯一のインスタンス return &instance; } virtual ~CacheManager() { } private: // 生成やコピーを禁止 CacheManager() { } CacheManager(const CacheManager& rhs); CacheManager& operator=(const CacheManager& rhs); }; #endif // __CacheManager__
// CacheManager.cpp #include "CacheManager.h" #include "Resource.h" static const string NONE = "None"; InterfaceResource* CacheManager::getRes(string name) { int empty_index = -1; bool passed = false; for(int i = 0; i < CACHE_MAX; ++i) { if(m_cache[i].Name == name) { // キャッシュにある ++m_cache[i].RefCount; return m_cache[i].resource; } else if(!passed && m_cache[i].Name == NONE) { passed = true; empty_index = i; } } // キャッシュに無い if(passed) { // 空いている場所に作成 ++m_cache[empty_index].RefCount; m_cache[empty_index].Name = name; m_cache[empty_index].resource = new Resource(name); return m_cache[empty_index].resource; } // キャッシュが一杯 return new Resource(name); } void CacheManager::releaseRes(InterfaceResource* (&res)) { if(!res) return; for(int i = 0; i < CACHE_MAX; ++i) { if(m_cache[i].Name == res->getName()) { --m_cache[i].RefCount; res = 0; // ここが厄介なのでポインタを参照渡し if(m_cache[i].RefCount < 1) { delete m_cache[i].resource; m_cache[i].resource = 0; m_cache[i].RefCount = 0; m_cache[i].Name = NONE; } return; } } // キャッシュに無い delete res; res = 0; } void CacheManager::dispCache() { for(int i = 0; i < CACHE_MAX; ++i) { cout << i << " : " << m_cache[i].RefCount << ", " << m_cache[i].Name << ", " << m_cache[i].resource << endl; } } void CacheManager::init() { for(int i = 0; i < CACHE_MAX; ++i) { m_cache[i].RefCount = 0; m_cache[i].Name = "None"; m_cache[i].resource = 0; } }