Roc*_*net 43 c++ lambda lifetime c++11
以下 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();
}
Run Code Online (Sandbox Code Playgroud)
Gui*_*cot 52
您不是存储 lambda,而是存储对std::function
.
事实上,std::function
当 lambda 隐式转换为std::function
. 该std::function
临时对象在调用构造函数的行之后终止。
LambdaStore(const std::function<void(float)>& _fn) // _fn refers to a temporary
: fn(_fn)
{
fn(11.1f); // works
} // fn (and _fn) dies
Run Code Online (Sandbox Code Playgroud)
但是,即使您将类更改为通过模板直接使用 lambda 类型,lambda 本身也会消失,但对于任何 C++ 类型来说都是如此,无论是什么类型。考虑int
s:
class LambdaStore
{
public:
LambdaStore(const int& _i)
: i(_i)
{
std::cout << i; // works
}
void ExecuteStoredLambda()
{
std::cout << i; // crashes
}
private:
const int& i;
};
void main()
{
LambdaStore lambdaStore(1); // temporary int created here
// temporary int gone
lambdaStore.ExecuteStoredLambda();
}
Run Code Online (Sandbox Code Playgroud)
当临时变量绑定到函数参数时,它们的生命周期不会超过为其创建的语句。
但是,如果它直接绑定到成员引用,则它们确实会获得生命周期延长,但仅使用大括号时:
struct ref {
const int& i
};
int main() {
ref a{3};
std::cout << a.i; // works
ref b(3);
std::cout << b.i; // crashes
}
Run Code Online (Sandbox Code Playgroud)
解决方案显然是按值存储std::function
而不是按引用存储:
class LambdaStore
{
public:
LambdaStore(const std::function<void(float)>& _fn)
: fn(_fn)
{
fn(11.1f); // works
}
void ExecuteStoredLambda()
{
fn(99.9f); // will also work
}
private:
std::function<void(float)> fn; // no & here
};
Run Code Online (Sandbox Code Playgroud)
拉姆达函数
这可能是你的理解误入歧途的地方。Lambda 是具有成员函数的对象;它们本身并不是函数。operator()
它们的定义看起来像函数体,但这实际上是对象的调用运算符 的定义。
您对场景的评估的半修正版本:
lambda对象似乎在构造函数内正确调用了其运算符,但后来,同一个对象不再起作用!
为什么只是“半”修正?因为在内部LambdaStore
,您不能直接访问 lambda 对象。相反,您可以通过对象(引用)来访问它std::function
。更正确的版本:
该
std::function
对象似乎在构造函数内正确调用了其运算符,但后来,同一个对象不再工作!
如果我去掉“lambda”的概念,也许这会更清楚?您的主要功能基本上是以下功能的语法快捷方式。
struct Functor {
void operator()(float a) {
cout << a << endl;
}
};
int main()
{
LambdaStore lambdaStore(Functor{});
lambdaStore.ExecuteStoredLambda();
}
Run Code Online (Sandbox Code Playgroud)
在此版本中,应该更容易看到您创建了一个临时对象作为LambdaStore
构造函数的参数。(实际上,您创建了两个临时对象 - 显式Functor
对象和隐式std::function<void(float)>
对象。)然后您可能会注意到,您存储的引用在构造函数完成后立即变为悬空......
lambda 的寿命有限制吗?
是的。这个 lambda 是一个临时对象(并且不受生命周期延长的影响),因此它的生命周期非常有限。
是的,临时变量(包括 lambda)的生命周期是有限的,并且引用并不能使其保持活动状态。您可能想存储一个副本。int
您的问题与您存储引用的任何其他临时变量(例如 a )相同。如果引用的变量要在引用的生命周期内有效,则它必须比引用的生命周期长。
在构造函数中,您引用了一个函数;这就是正在存储的内容。ExecuteStoredLambda()
由于传递给构造函数的函数是内联函数,因此在调用时对它的引用不再有效。要使其工作,请传入非内联函数,或者更好的方法是将fn
成员更改为对象实例而不是引用。即
const std::function<void(float)> fn;
(没有&)
归档时间: |
|
查看次数: |
6361 次 |
最近记录: |