c ++ lambda按值捕获

Law*_*nce 18 c++ c++11

我正在阅读本书第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;
Run Code Online (Sandbox Code Playgroud)

这段代码打印出来:

x: 0
y: 77
x: 0
y: 78
final y: 79
Run Code Online (Sandbox Code Playgroud)

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

vso*_*tco 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();
}
Run Code Online (Sandbox Code Playgroud)

Live on Coliru


344*_*442 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;
}
Run Code Online (Sandbox Code Playgroud)

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

#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;
}
Run Code Online (Sandbox Code Playgroud)

除了特殊的lambda语法和你不能直接引用lambda类型的事实.通过将前者与后面的代码进行比较,您应该能够清除对闭包的理解.


jdi*_*tal 7

lambda 在定义 lambda 时使用该值(它进行复制),而不是在调用时使用该值。

这可能会有所帮助:Lambda 闭包是如何实现的?