C++成员函数结果缓存实现

C++ Member Function Results Cache Implementation

本文关键字:缓存 实现 结果 函数 成员 C++      更新时间:2023-10-16

我有一些函数需要很长时间,但结果总是一样的,所以我想缓存结果。我已经编写了一个结果缓存的通用实现,它可以被继承,为派生类提供缓存功能。

#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);
}

在这里使用重新解释演员阵容安全吗?

如果使用std::map而不是std::vector来从名称中查找值,这会更快吗。我已经看到,在许多地方,由于预取器,std::vector的速度要快得多。

在许多地方,由于预取器,std::vector的速度要快得多。

我想你说的预取器是指CPU分支预测和L1缓存?或者你指的是别的什么?过映射的速度在很大程度上取决于缓存的大小和缓存中的项目。如果它的项目相对较少,那么向量可以更快,但如果不是,那么使用Map-当向量变大时,映射的O(log(n))或无序映射的0(1)将比O(n)更快。[如果它很小,你可能会更好地评估更简单的代码,而不是有限的性能增益。]

为了回答您最初的问题,重新解释将虚拟接口指针强制转换为具体类型是不安全的,因为如果您更改派生类的继承(例如,继承两个接口),编译器可能会修改vtable。您需要静态强制转换。