c++:为什么一个特定的参数必须由lambda中的值捕获

c++: why a specific parameter must be captured by value in lambda

本文关键字:参数 lambda 为什么 一个 c++      更新时间:2023-10-16
#include <iostream>
#include <functional>
#include <utility>
using namespace std;
typedef std::function<void(const string&, const string&, const bool, const bool)> 
Callback_T;
class A {
public:
void
process(const string &a, const string &b, const bool c, const bool d, const int e)
{
cout << "a: " << a << " b: " << b << " c: " << c << " d: " << d << " e: " << e << endl;
}
Callback_T
constructCallback(const int &e)
{
Callback_T callback =
[&, this, e](auto&&...args) // <--- here, e must be captured by value, why?
{
this->process(
std::forward<decltype(args)>(args)...,
e);
};
return callback;
}
};
int main()
{
A a;
auto cb = a.constructCallback(20);
cb("A", "B", true, false);
}

上述程序输出:"a:Ab:Bc:1 d:0 e:20"但如果我把捕获e的行改为:

[&,this,&e]

它输出:"a:Ab:Bc:1 d:0 e:263440408",似乎表明e未定义/初始化。

为什么只通过有价值的作品来捕捉它?

您所拥有的是一个悬空引用。由于e是一个参考参数,它与其他参数绑定。在这种情况下,它是根据文字20创建的临时对象。当函数结束,留下callback并引用一个不再存在的对象时,这个临时性就超出了作用域。

当您通过值捕获时,您否定了这个问题,因为lambda将存储它自己的e副本,以确保它在constructCallback返回后仍然有效。


通过引用捕获时,必须确保没有任何路径会留下对不存在的东西的引用。

因为调用函数时e超出了作用域,并且您有一个悬空引用。在以下行中:

A a;
auto cb = a.constructCallback(20);
cb("A", "B", true, false);

调用constructCallback(20)时,会创建一个值为20的本地e,该值通过引用lambda捕获,然后在函数退出时销毁。因此,使用此引用是未定义的行为,并导致您观察到的垃圾值。如果改为按值捕获e,则它将被复制,并且与lambda一样长。如果您确实需要通过引用使用e,则需要确保在计算lambda之前它不会被破坏。