下面的C++代码打印11.1
然后崩溃。lambda函数似乎在构造函数中被正确调用,但后来,同一个函数不再起作用!为什么会这样呢?Lambda的寿命有限吗?
#include <functional>
#include <iostream>
class LambdaStore
{
public:
LambdaStore(const std::function<void(float)>& _fn)
: fn(_fn)
{
fn(11.1f); // works
}
void ExecuteStoredLambda()
{
fn(99.9f); // crashes
}
private:
const std::function<void(float)>& fn;
};
int main()
{
LambdaStore lambdaStore([](float a) { std::cout << a << '\n'; });
lambdaStore.ExecuteStoredLambda();
}
字符串
4条答案
按热度按时间0dxa2lsx1#
你不是在存储lambda,你是在存储对
std::function
的引用。实际上,当lambda被隐式转换为
std::function
时,std::function
被创建为临时变量。该std::function
临时在调用构造函数的行之后死亡。字符串
但是,即使你通过模板直接使用lambda类型来改变你的类,lambda本身也会死,但这对任何C++类型都是正确的,不管是什么类型。考虑
int
s:型
当临时对象绑定到函数参数时,它们的生存期不会超过为其创建的语句。
如果它们直接绑定到成员引用,则它们确实会获得生存期扩展,但仅使用大括号时:
型
解决方案显然是通过值而不是引用来存储
std::function
:型
5kgi1eie2#
lambda函数
这可能是你的理解误入歧途的地方。Lambda是对象成员函数;它们本身不是函数。它们的定义看起来像函数体,但实际上是对象的调用操作符
operator()
的定义。你对这个场景的评估的一个半修正版本:
为什么只有“半”纠正?因为在
LambdaStore
中,您不能直接访问lambda对象。相反,您可以通过std::function
对象(引用)访问它。更正确的版本:**
std::function
*对象似乎在构造函数中正确调用了它的运算符,但后来,同一个对象不再工作!如果我把lambda的概念去掉,也许这会更清楚?你的main函数基本上是以下内容的语法捷径。
字符串
在这个版本中,应该更容易看到您创建了一个临时对象作为
LambdaStore
构造函数的参数。(实际上,您创建了两个临时对象--显式Functor
对象和隐式std::function<void(float)>
对象。)然后您可能会注意到,您存储了一个引用,该引用在构造函数完成后立即变为悬空引用。Lambda的寿命有限吗?
是的,在C++中,具有非静态存储持续时间的对象具有有限的生命周期。
avwztpqn3#
是的,临时变量(包括lambda)的生命周期是有限的,引用并不能保持它的生命周期。您可能需要存储一个副本。您的问题与存储引用的任何其他临时变量(如
int
)相同。被引用的变量必须比引用的寿命长,才能在引用的生命周期内有效。qcbq4gxm4#
在构造函数中,你引用了一个函数;这就是被储存的东西。因为传递给构造函数的函数是一个内联函数,所以在调用
ExecuteStoredLambda()
时,对它的引用不再有效。要使其工作,传入一个非内联函数,或者更好的方法是将fn
成员更改为对象示例而不是引用。即const std::function<void(float)> fn;
(无&)