我有一些功能需要很长时间,但结果总是一样的,所以我想缓存结果。我编写了一个结果缓存的通用实现,可以继承,为派生类提供缓存功能。
#include "includes.h"
// Interface so values can be stored polymophically in a vector
class CacheInterface
{
public:
virtual ~CacheInterface(){}
virtual std::string GetName() const = 0;
};
// Stores a cached value and its name
template <class T>
class CachedValue : public CacheInterface
{
public:
CachedValue(const T & value, const std::string & name):
_value(value),
_name(name)
{
}
std::string GetName() const
{
return _name;
}
void SetValue(const T & value)
{
_value = value;
}
T _value;
std::string _name;
};
// Stores the cache results, can be inherited from or held as a member.
class ResultCache
{
public:
template <class T> void AddToCache(const T & value, const std::string & name)
{
// Search if it is there
for (shared_ptr<CacheInterface> & cache : _cached_items)
{
if (cache->GetName() == name)
{
shared_ptr<CachedValue<T>> cache_value (boost::reinterpret_pointer_cast<CachedValue<T>>(cache));
cache_value->_value = value;
return;
}
}
// Make a new cache value and add it
shared_ptr<CacheInterface> cached_item(new CachedValue<T>(value, name));
_cached_items.push_back(cached_item);
}
// Returns true if cache exists for a name
bool IsInCache(const std::string & name)
{
for (shared_ptr<CacheInterface> & cache : _cached_items)
{
if (cache->GetName() == name)
{
return true;
}
}
return false;
}
// Reads a value from the cache
template <class T> void ReadFromCache(T & output, const std::string & name)
{
for (shared_ptr<CacheInterface> & cache : _cached_items)
{
if (cache->GetName() == name)
{
// Is reinterpret cast safe?
shared_ptr<CachedValue<T>> cache_value (boost::reinterpret_pointer_cast<CachedValue<T>>(cache));
output = cache_value->_value;
}
}
}
// Clears the cache values
void ClearCache()
{
_cached_items.clear();
}
// Clear cache on copy and assign?
private:
std::vector<shared_ptr<CacheInterface>> _cached_items;
};
// Macros simplified use in code.
#define IS_IN_CACHE(x) IsInCache(#x)
#define READ_FROM_CACHE(x) ReadFromCache(x, #x)
#define CACHE_RESULT(x) AddToCache(x, #x)
用法:
#include "UnitTest++.h"
#include "resultcache.h"
#include "accuratetimer.h"
class TestCacheClass : public ResultCache
{
public:
int LongFunction()
{
int i = 34;
if (IS_IN_CACHE(i))
{
READ_FROM_CACHE(i);
return i;
}
else
{
sleep(1);
i = 9932;
CACHE_RESULT(i);
return i;
}
}
};
TEST(Cache1)
{
TestCacheClass test_class;
AccurateTimer timer;
CHECK_EQUAL(test_class.LongFunction(), 9932);
CHECK_CLOSE(timer.GetTimeDuration(), 1.0, 0.2);
timer.Reset();
CHECK_EQUAL(test_class.LongFunction(), 9932);
CHECK_CLOSE(timer.GetTimeDuration(), 0.0, 0.2);
}
在这里使用reinterpret cast安全吗?
如果使用std :: map而不是std :: vector,从名称中查找值,这会更快吗?我已经看到,在很多地方,由于预取器,std :: vector的速度要快得多。
答案 0 :(得分:0)
在很多地方,由于预取器,std :: vector的速度要快得多。
通过prefetcher,我假设您的意思是CPU分支预测和L1缓存?或者你指的是其他什么?映射的速度很大程度上取决于缓存的大小和缓存中的项目。如果它的项目相对较少,那么矢量可以更快,但如果没有,则使用Map - 当矢量变大时,地图的O(log(n))或无序地图的O(1)将更快比O(n)。 [如果它很小,你可能最好不要考虑更简单的代码而不是有限的性能提升。 ]
要回答原始问题,将虚拟接口指针重新解释为具体类型是不安全的,因为如果更改派生类的继承,编译器可以修改vtable(例如,继承两个接口) )。你想要静态演员。