我认为这是众所周知的解决方案的一个常见问题,我不是 能够找到。所以我在这里寻求建议。
请考虑以下设置:
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)
的调用将在不同的范围内。
以下是我探索过的解决方案,以及它的价值。
我可以想象一个简单的解决方案,包括向类A
添加时间戳
函数f
可以检查并确定是否需要更新其缓存结果,
存储在中央缓存中的某个位置。我想这也意味着改变了
f
的签名:
const A& f(const A&);
问题1:使用中央缓存,我们需要一种机制来销毁
<{1}}被销毁时f(a)
的缓存结果。
除问题1外,这似乎很简单。但是a
时会变得复杂
代表A
。我想应该排除动态多态性
这里。所以我们忘记了为std::vector<...>
的所有子类添加时间戳
最重要的是它意味着什么。但是,我们可以计算一些哈希码或UUID
基于std::vector<...>
的内容---假设它比计算便宜得多
a
---并将中央缓存基于这些哈希码。但是我们正面临着
问题1了。
我还没有找到如何实现这一点,但想法是f(a)
通知
写入或销毁a
时f(a)
的缓存,但不是。{
只是阅读。没有动态多态,我无法想象如何做到这一点,
并且不使用a
或者减慢单元素访问速度
迭代器通过向每个已修改元素的缓存发送通知。
问题2:找到一种机制,用于将更改集分隔为operator[]
,以便为每组更改使缓存无效。
我已经考虑过在a
上启用写访问的代理(受到这个概念的启发
of mutex),但无法提出任何有效的代码。
有什么想法吗?
答案 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的实例中决定是否可以重复使用缓存的结果。