C++ 是C++;11 Lambda自身是否受RAII自动解除分配的约束?

C++ 是C++;11 Lambda自身是否受RAII自动解除分配的约束?,c++,c++11,lambda,raii,C++,C++11,Lambda,Raii,我想编写一个类方法,可以选择接受lambda来定制其行为。所以在使用这个类时,我想知道是否需要担心lambda本身超出了范围 lambda不会引用任何外部变量,所以我不担心变量的范围,只担心lambda本身的范围,我会在类中存储对它的引用 我是否需要担心lambda本身是如何/在何处创建的?除了狭隘的情况外,引用不会延长所引用对象的生命周期 使用对生命周期已过期的对象的引用是未定义的行为 无状态lambda的未定义行为可能是“我甚至不使用我的this指针”,因此您可能会没事。但是,如果您知道la

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

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


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

除了狭隘的情况外,引用不会延长所引用对象的生命周期

使用对生命周期已过期的对象的引用是未定义的行为

无状态lambda的未定义行为可能是“我甚至不使用我的
this
指针”,因此您可能会没事。但是,如果您知道lambda将是无状态的,则可以存储函数指针

现在,为了存储实际的lambda,您的类必须以该lambda类型为模板。如果它是一个无状态lambda,那么它几乎肯定会和对该lambda的引用一样小(或更小)。那为什么不储存一份lambda的拷贝呢


相反,如果您存储的是
std::function
等,则这不是对lambda的引用。这是一个类型擦除对象,用于包装lambda的副本。在
std::function
超出范围后存储对该函数的引用是个坏主意,因为它不是无状态的,当您尝试调用它时,它将关闭并读取垃圾内存。

可能无法完全填充您的答案,但请看一下herb sutter如何使用lambdas解决类似的RAII问题。也见此

模板类锁定器{
私人:
可变T m\u T;//在此处复制lambda。
可变std::互斥m_m;
公众:
locker(T=T{}):m_T(T{}
模板
自动运算符(){
std::锁紧装置{m{m};
返回f(t);
}
};
//用法
储物柜;
s([](字符串和s){
s+=“foobar”;
s+=“巴福”;
});

这个示例的重要部分是复制Lambda。您不应该持有对lambdas的引用,因为函数本身将位于程序的只读部分。lambda保存的唯一数据是函数指针及其捕获。如果确实有捕获,则取决于lambda的作用域,如果超出了作用域,则将访问已释放的内存。

我认为函数本身永远不会超出作用域。lambda只是函子对象的闪亮语法。它将归结为一个函数指针。不要保留对lambda的引用,但要保留一份副本。如果捕获列表是空的,那么它将是便宜的。一般来说,这些类型的问题最好与您尝试执行的代码示例一起解决。这是它自己独特的类类型的实例。它遵循与任何其他实例相同的对象生存期规则。您是否需要“担心”这完全取决于您如何使用它,我们对此一无所知。函子通常应该通过值来处理,而不是通过引用来处理。Lambda表达式只是创建函子的一种简便方法,因此您也应该将Lambda的结果作为值来处理。Lambda不包含函数指针:它们的
运算符()
是其类型的一部分,而不是其运行时状态。@YakK:我要重新表述一下,我要指出的是,编译器将生成跳转到标签的代码,而该标签可能不在二进制文件的只读部分。什么?呵呵?从C++11开始,lambda代码“不在二进制文件的只读部分”的原因并不比任何其他代码“不在二进制文件的只读部分”的原因多。(C++1y中有一些建议,比如指向有状态lambda调用的函数指针,可能需要类似的东西)。只读部分中可能没有的唯一内容是存储、复制或引用捕获列表中变量的标签。其他一切都很好。这并不是说您需要自修改代码或ram函数来实现可能泄漏或超出范围的lambda。@Alex:“跳到标签”表示标签位于代码段中;要么是只读代码段,要么是读/写代码段。后者意味着自修改代码。你的两条评论相互矛盾。
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";
});