c ++ lambda按值捕获

时间:2016-06-05 00:35:48

标签: c++ c++11

我正在阅读this book第3章中的C ++ lambda部分,下面的代码让我感到困惑:

int x = 0;
int y = 42;
auto qqq = [x, &y] {
    std::cout << "x: " << x << std::endl;
    std::cout << "y: " << y << std::endl;
    ++y;
};
x = y = 77;
qqq();
qqq();
std::cout << "final y: " << y << std::endl;

此代码打印出来:

x: 0
y: 77
x: 0
y: 78
final y: 79

为什么qqq()没有注册x已经改为77?据说,通过值传递意味着我们可以读取但不能修改定义lambda的数据。这是否意味着我们无法在其定义后看到变化?

3 个答案:

答案 0 :(得分:19)

这是因为当你定义lambda时,变量只被值(即复制)捕获一次。它可能不会像您所认为的那样“更新”。代码大致相当于:

#include <iostream>

int x = 0;
struct Lambda
{
    int _internal_x; // this is used to "capture" x ONLY ONCE
    Lambda(): _internal_x(x) {} // we "capture" it at construction, no updates after
    void operator()() const
    {
        std::cout << _internal_x << std::endl;
    }
} qqq; 

int main()
{
    qqq(); 
    x = 77; // this has no effect on the internal state of the lambda
    qqq();
}

Live on Coliru

答案 1 :(得分:11)

通过将值变量绑定到lambda闭包,您可以有效地将变量的值复制到lambda对象中的单独变量中。同样,通过引用绑定变量,您将使这样的内部变量成为对原始变量的引用,从而能够“看到原始变量的变化”。

这样看。以下代码......

#include <iostream>

int main()
{
    int x = 0;
    int y = 42;
    auto qqq = [x, &y] {
        std::cout << "x: " << x << std::endl;
        std::cout << "y: " << y << std::endl;
        ++y;
    };
    x = y = 77;
    qqq();
    qqq();
    std::cout << "final y: " << y << std::endl;
}

(...的种类,但不完全是)语法糖...

#include <iostream>

class MyLambda
{
    private:
        int x;
        int& y;

    public:
        MyLambda(int x, int& y) : x(x), y(y) {}

        void operator()()
        {
            std::cout << "x: " << x << std::endl;
            std::cout << "y: " << y << std::endl;
            ++y;
        }
};

int main()
{
    int x = 0;
    int y = 42;
    MyLambda qqq = MyLambda(x, y);
    x = y = 77;
    qqq();
    qqq();
    std::cout << "final y: " << y << std::endl;
}

除了特殊的lambda语法和你不能直接引用lambda的类型这一事实。通过比较前者和后面的代码,您应该能够清楚地了解闭包。

答案 2 :(得分:4)

lambda使用lambda定义时的值(它创建一个副本),而不是在调用它时。

这可能会有所帮助:How are Lambda Closures Implemented?