【发布时间】:2019-01-18 09:48:46
【问题描述】:
让代码先用幼稚的方法自己说话:
int heavy_calc() // needed to be called once
{
// sleep(7500000 years)
return 42;
}
int main()
{
auto foo = [] {
// And cached for lambda return value
static int cache = heavy_calc();
return cache;
};
return foo() + foo();
}
我想在第一次调用时计算 lambda 内部缓存值。一种天真的方法是使用static 缓存,但它是increases binary size and refuses to be be inlined。
我想出了在捕获列表中创建 cache 并将 lambda 标记为 mutable,什么是 inlines without problems,但需要缓存以默认值开始,这可能会破坏类不变量。
auto foo = [cache=0] () mutable {
// And cached for lambda return value
if(!cache)
cache = heavy_calc();
return cache;
};
我的第三种方法使用boost::optional in mutable lambda
auto foo = [cache=std::optional<int>{}] () mutable {
// And cached for lambda return value
if(!cache)
cache = heavy_calc();
return *cache;
};
它可以正常工作,但将我视为一种捕获列表 + mutable 关键字黑客。此外,mutable 会影响所有捕获的参数,因此会降低 lambda 在实际使用中的安全性。
也许对此有更好/更干净的解决方案?或者只是不同的方法最终会产生相同的效果。
编辑,一些背景:
选择 Lambda 方法是因为我正在修改一些回调 lambda,目前用作:
[this, param]{this->onEvent(heavy_calc(param));}
我想减少 heavy_calc 调用而不提前评估它(仅在第一次调用时)
【问题讨论】:
-
heavy_calc 应该在 lambda 内部调用一次,还是可以在外部调用? (出于线程安全原因提出问题)
-
我想只在内部调用它。我没有考虑线程安全,但是另一个具有线程安全的天真解决方案是
thread_local而不是static,对吧? -
从线程安全的角度来看,您的静态答案是可以的。据我所知,在 C++11 中,可以保证静态变量的线程安全初始化。另一种选择是使用 call_once en.cppreference.com/w/cpp/thread/call_once 但我会使用静态。
-
所以 thread_local 和 static 都可以。我关于线程安全的问题与应该调用什么线程有关。你回答说应该从调用第一个 lambda 函数的线程中调用它。