用于函数输出的C ++简单缓存设计

时间:2011-07-01 06:19:07

标签: c++ caching

我认为这是众所周知的解决方案的一个常见问题,我不是 能够找到。所以我在这里寻求建议。

问题陈述

请考虑以下设置:

class A; // some class

const A f(const A&); // an _expensive_ function

void do_stuff()
{
    A a;

    a.modify(...);

    do_stuff1(f(a));  // compute f(a)
    do_stuff2(f(a));  // use cached value of f(a)

    a.modify(...);

    do_stuff3(f(a));  // recompute f(a)
}

我希望f(a)的返回值缓存在第一个和第一个之间 第二次呼叫,但在第二次呼叫a.modify()后被丢弃。 编辑:实际上,对f(a)的调用将在不同的范围内。

以下是我探索过的解决方案,以及它的价值。

解决方案1:中央缓存

使用时间戳

我可以想象一个简单的解决方案,包括向类A添加时间戳 函数f可以检查并确定是否需要更新其缓存结果, 存储在中央缓存中的某个位置。我想这也意味着改变了 f的签名:

const A& f(const A&);

问题1:使用中央缓存,我们需要一种机制来销毁 <{1}}被销毁时f(a)的缓存结果。

使用哈希码

除问题1外,这似乎很简单。但是a时会变得复杂 代表A。我想应该排除动态多态性 这里。所以我们忘记了为std::vector<...>的所有子类添加时间戳 最重要的是它意味着什么。但是,我们可以计算一些哈希码或UUID 基于std::vector<...>的内容---假设它比计算便宜得多 a ---并将中央缓存基于这些哈希码。但是我们正面临着 问题1了。

解决方案2:耦合对象

我还没有找到如何实现这一点,但想法是f(a)通知 写入或销毁af(a)的缓存,但不是。{ 只是阅读。没有动态多态,我无法想象如何做到这一点, 并且不使用a或者减慢单元素访问速度 迭代器通过向每个已修改元素的缓存发送通知。

问题2:找到一种机制,用于将更改集分隔为operator[],以便为每组更改使缓存无效。

我已经考虑过在a上启用写访问的代理(受到这个概念的启发 of mutex),但无法提出任何有效的代码。

有什么想法吗?

4 个答案:

答案 0 :(得分:2)

我用这样的接口做了类似的事情:

class F
{
public:
 virtual int f(int a)=0;
};

class Cache : public F
{
public:
   Cache(F &f) : f(f) { }
   int f(int a) { /*caching logic here, calls f.f() if not found from cache */ }
   F &f;
};

class Impl : public F
{
   int f(int a) { /* real implementation here */ }
};

然后就决定在哪里使用缓存逻辑:

   Impl i; 
   Cache c(i);
   c.f(10); // put to cache with key 10
   c.f(10); // found from cache
   c.f(11); // put to cache with key 11

答案 1 :(得分:1)

你不能这样做:

const A &cacheA = f(a);
do_stuff1(cacheA);  // compute f(a)
do_stuff2(cacheA);  // use cached value of f(a)

答案 2 :(得分:1)

我可能在这里遗漏了一些重要的细节,但你不能只为此目的使用LRU cache吗?

答案 3 :(得分:1)

使f成为A的成员。然后,您可以在A的实例中决定是否可以重复使用缓存的结果。