我想编写一个类方法,可以选择接受lambda来自定义它的行为。所以当使用这个类时,我想知道我是否需要担心lambda本身超出范围?
lambda不会引用任何外部变量,所以我不担心变量的范围,只关于lambda本身的范围,我将在类中存储引用。
我是否需要担心lambda本身的创建方式/位置?
答案 0 :(得分:2)
在狭隘情况之外,引用不会延长您引用的东西的生命周期。
使用对生命周期已过期的内容的引用是未定义的行为。
无状态lambda的未定义行为可能是“我甚至不使用我的this
指针”,所以你可能没事。但是,如果你知道lambda将是无状态的,你可以改为存储一个函数指针。
现在,为了存储实际的lambda,你的类必须在该lambda类型上进行模板化。如果它是一个无状态的lambda,它几乎肯定会比那个lambda的引用小(或更小)。那么为什么不只是存储lambda的副本?
如果您要存储std::function<void()>
等,那么这不是对lambda的引用。这是一个包装lambda副本的类型擦除对象。在std::function<void()>
超出范围后存储引用将是一个坏主意,因为它不无状态,并且当您尝试调用它时将关闭并读取垃圾内存。
答案 1 :(得分:1)
可能没有完全填写你的答案,但看看草药sutter如何用lambdas解决方案解决了类似的RAII。另见SO Question
template <class T> class locker {
private:
mutable T m_t; // Copies the lambda here.
mutable std::mutex m_m;
public:
locker( T t = T{} ) : m_t(t) {}
template <typename F>
auto operator()(F f) const -> decltype(f(m_t)) {
std::lock_guard<mutex> _{m_m};
return f(t);
}
};
// usage
locker<std::string> s;
s([](string &s) {
s += "foobar";
s += "barfoo";
});
关于这个例子的重要部分是Lambda被复制了。您不应该持有对lambdas的引用,因为函数本身将位于程序的只读部分。 lambda拥有的唯一数据是函数指针及其捕获。如果你确实有捕获,那么你依赖于lambda的范围,如果这个范围超出范围,你就会访问已经发布的内存。