C++11 λ 本身是否受 RAII 自动释放的影响

Are C++11 lambdas themselves subject to RAII automatic deallocation?

本文关键字:释放 影响 RAII 是否 C++11      更新时间:2023-10-16

我想编写一个类方法,可以选择接受lambda来自定义其行为。 所以在使用这个类时,我想知道我是否需要担心 lambda 本身超出范围?

lambda 不会引用任何外部变量,所以我不担心变量的范围,只担心 lambda 本身的范围,我会在类中存储对它的引用。

我是否需要担心 lambda 本身是如何/在哪里创建的?

在狭隘的情况下,引用不会延长所引用事物的生存期。

使用对生存期已过期的事物的引用是未定义的行为。

无状态 lambda 的未定义行为可能是"我什至不使用我的this指针",所以你可能没问题。 但是,如果您知道 lambda 将是无状态的,则可以改为存储函数指针。

现在,为了存储实际的 lambda,您的类必须在该 lambda 类型上进行模板化。 如果它是一个无状态的lambda,它几乎肯定会比对该lambda的引用一样小(或更小)。 那么为什么不只存储 lambda 的副本呢?

相反,如果您存储的是std::function<void()>或类似的东西,则不是对 lambda 的引用。 这是一个类型纠删节对象,它包装了一个 lambda 的副本。 在std::function<void()>超出范围后存储对它的引用将是一个坏主意,因为它不是无状态的,并且当您尝试调用它时会关闭并读取垃圾内存。

可能不会完全填写您的答案,但看看 Herb Sutter 如何用 lambda 解决方案解决类似的 RAII。另请参阅此 SO 问题

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。您不应该保留对 lambda 的引用,因为函数本身将位于程序的只读部分中。lambda 保存的唯一数据是函数指针及其捕获。如果您确实有捕获,则取决于 lambda 的范围,如果超出范围,您将访问内存,该内存已经释放。