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

标签 c++ caching c++11

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

#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/

相关文章:

c++ - 尝试使用 opencv c++ 绘制简单函数

c++ - 扑克代码清理修改从书...不太正确

php - 防止在 CloudFlare 中缓存

c# - 如何在 ASP.NET 缓存应用程序中超过 IIS7 的 60% 内存限制

c++ - 为构造函数重用可变参数模板

c++ - 指针、类项和范围

c++ - C 风格的字符串安全吗?

iOS:AFNetworking 的 AFHTTPSessionManager 缓存策略

c++ - 'using' 关键字从多个虚拟继承函数中进行选择

c++ - 我们可以使用 std::vector 定义一个固定宽度的二维矩阵吗?