我有一些函数需要很长时间,但结果总是一样的,所以我想缓存结果。我编写了一个结果缓存的通用实现,它可以被继承,为派生类提供缓存功能。
#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 的速度要快得多。
最佳答案
in many places a std::vector is much faster due to the pre-fetcher.
我假设预取器是指 CPU 分支预测和 L1 缓存?或者你指的是别的东西? over map 的速度在很大程度上取决于缓存的大小和缓存中的项目。如果项目相对较少,那么 vector 可能会更快,但如果不是,则使用 Map - 当 vector 变大时,map 的 O(log(n)) 或无序 map 的 O(1) 将比 O(n ). [如果它很小,您最好评估更简单的代码而不是有限的性能提升。 ]
要回答您最初的问题,将虚拟接口(interface)指针重新解释为具体类型是不安全的,因为如果您更改派生类的继承(例如,继承两个接口(interface)),编译器可能会修改 vtable。你想要静态转换。
关于C++ 成员函数结果缓存实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26540971/