在捕获' []'中编写lambda函数时第一部分我需要只指定自动持续时间变量,而全局和静态变量在lambda函数中使用而不需要捕获。这是为什么?为什么我们不能像全局变量和静态变量一样使用自动持续时间变量?
答案 0 :(得分:5)
因为lambda定义了一个单独的范围:它等同于:
int global_i;
struct Lambda {
Lambda(int captured_j) : captured_j(captured_j) {}
void operator()(){
// in this scope, global_i is accessible, and by capturing auto_j, we make that visible as well, but we can't see auto_i
}
int captured_j;
}
void foo() {
int auto_i;
int auto_j
// this lambda
[j](){}
// is just shorthand for this:
Lambda lambda(j);
}
lambda由编译器转换为一个函数对象(就像我的例子中的Lambda
类)。并且函数对象无法访问在实例化函数对象的范围内声明的局部变量。除非你通过将它们传递给构造函数来“捕获”它们。
至于编译器为什么不隐式执行此操作而不要求您提示它,它不能,因为它不知道您是想要按值还是通过引用捕获。在GC语言中,您总是通过引用捕获,因为它无关紧要 - 只要您需要它们,您引用的对象就会保持活动状态。
但是在C ++中,你需要管理那些对象的生命周期,如果一个lambda总是通过引用捕获,那么它在声明范围之外几乎是无用的(因为它将包含对已被破坏的对象的引用) )。因此,在C ++中,您必须指定是否要按值或引用进行捕获。因为你必须指定它,编译器不能只为你做。
答案 1 :(得分:2)
考虑这个简单的功能:
std::function<foo()> f()
{
foo afoo;
return [=](){ return afoo; };
}
int main()
{
auto l = f();
l();
}
如果您没有捕获变量afoo
,那么在使用lamda形成的闭包之前它会超出范围!
另请注意,我使用by-value capture完全出于同样的原因:返回引用/指向局部变量的指针具有未定义的行为。
答案 2 :(得分:1)
基本上,关于lambda的魔力并不大;简单地认为它是一个匿名的仿函数。
传统的仿函数也不知道它所包含的局部变量,你需要将它们提供给它的ctor。像lambda这样的匿名事物没有可自定义的c,因此你通过这个&#34; []&#34;提供了上下文。语法。
或考虑
const float g_foo = 42.f;
struct A {
float _bar;
struct B {
B() : _baz(_bar /*oops*/) {}
float _baz;
};
};
在A :: B关闭时,没有A&#34; _bar&#34;的概念,但g_foo会被人知道。