C ++ 11 lambda - 为什么我需要捕获自动持续时间变量?

时间:2014-06-29 11:15:05

标签: c++ c++11 lambda

在捕获' []'中编写lambda函数时第一部分我需要只指定自动持续时间变量,而全局和静态变量在lambda函数中使用而不需要捕获。这是为什么?为什么我们不能像全局变量和静态变量一样使用自动持续时间变量?

3 个答案:

答案 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会被人知道。