捕获列表中捕获的行为[c ++]

时间:2015-10-25 20:37:31

标签: c++ lambda

我对capturescapture-list的行为感到困惑。

#include <iostream>
using namespace std;

int main()
{
    int a = 1, b = 1, c = 1;

    auto m = [a, &b, &c]() mutable
    {
        std::cout << a << b << c << '\n';  // prints 122
        a = 3; b = 3; c = 3;
    };

    a = 2; b = 2; c = 2;

    m();                              
    std::cout << a << b << c << '\n';     // prints 233
}

输出:

122
233 

如果lambda函数在另一个函数内声明:

auto m1 = [a, &b, &c]() mutable
{
    auto m2 = [a, b, &c]() mutable
    {
        std::cout << a << b << c << '\n';
        a = 4; b = 4; c = 4;
    };

    a = 3; b = 3; c = 3;
    m2();
};

据我所知,

  • 定义lambda函数时,by-copy捕获初始化为其当前值。
  • by-reference在调用函数时初始化捕获。
  • by-copy捕获不会影响其阻止。
  • by-reference捕获可以更改其原始值。

我是对的吗?我已经学过,但我没有明白。任何人都可以解释一下吗?

2 个答案:

答案 0 :(得分:2)

在这个lambda表达式中

auto m = [a, &b, &c]() mutable
{
    std::cout << a << b << c << '\n';  // prints 122
    a = 3; b = 3; c = 3;
};

创建的对象有自己的a副本。定义对象时,变量a的值为1。

对于另外两个变量,该对象包含引用。

您可以通过以下方式想象lambda表达式

int a = 1, b = 1, c = 1;

class Unnamed
{
private:
    int a;
    int &b;
    int &c;
public:
    Unnamed( int a, int &b, int &c ) : a( a ), b( b ), c( c )
    {
    }

    void operator ()()
    {
        std::cout << a << b << c << '\n';  // prints 122
        a = 3; b = 3; c = 3;
    }
} m( a, b, c );        

因此,lambda对象定义之后a的任何更改都不会影响对象的相应数据成员。但是,当变量bc被更改时,对象的相应运算符函数的输出将反映这些变化。

所以在这些陈述之后

a = 2; b = 2; c = 2;

此次电话

 m();

将输出由变量a的前一个值初始化的对象的自己的数据成员的值以及bc的当前值,因为它包含对这些的引用变量

所以输出是

122

第二个输出

std::cout << a << b << c << '\n';

反映了变量abc的当前值2,3和3,因为在前面调用lambda变量bc已被更改。所以你得到了

233

答案 1 :(得分:2)

lambda实际上只是功能对象的语法糖。您的代码等同于

int main()
{
    int a = 1, b = 1, c = 1;

    struct {
        int a;
        int& b;
        int& c;
        void operator()()
        {
            std::cout << a << b << c << '\n';  // prints 122
            a = 3; b = 3; c = 3;
        }
    } m{a, b, c};

    a = 2; b = 2; c = 2;

    m();
    std::cout << a << b << c << '\n';     // prints 233
}

这不是严格的解释。如果Lambda没有捕获,则可以将其转换为函数指针。但在特定的例子中,这是正确的