#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:A b:B c:1 d:0 e:20” 但是,如果我将捕获e的行更改为:
[&,this,&e]
它输出:“ a:a b:B c:1 d:0 e: 26340408 ”,似乎表明e尚未定义/初始化。
为什么仅按价值捕获它有效?
答案 0 :(得分:3)
您所拥有的只是一个悬挂的参考。由于e
是参考参数,因此它绑定到其他对象。在这种情况下,它是根据文字20
创建的临时对象。当函数结束callback
并引用不再存在的对象时,此临时变量将超出范围。
当您按值捕获时,您可以取消此问题,因为lambda将存储它自己的e
副本,以确保constructCallback
返回后它仍然有效。
通过引用捕获时,必须确保没有路径会留下对不存在的内容的引用。
答案 1 :(得分:0)
因为e
在调用函数时超出范围,所以您有一个悬空的引用。在以下几行中:
A a;
auto cb = a.constructCallback(20);
cb("A", "B", true, false);
在调用constructCallback(20)
时,将创建一个本地e
,其值为20,该值通过引用您的lambda捕获,然后在函数退出时销毁。因此,使用此引用是未定义的行为,并导致您观察到的垃圾值。如果改为按值捕获e
,它将被复制,并且生存期与lambda一样长。如果确实需要通过引用使用e
,则需要确保在评估lambda之前不会破坏它。