C++ 理解可变捕获

C++ 理解可变捕获,c++,c++11,lambda,C++,C++11,Lambda,如果我理解正确(我的源代码是《C++初级读本》第5版第395页),《代码》可变版本可以从lambda中修改捕获的变量。有两件事我不明白: 这与通过引用捕获有什么不同?而且,如果通过引用捕获是下面发生的事情,那么mutable的目的是什么?只是一块糖 如果mutable可以在每个变量的基础上应用,不是更有帮助吗 mutable允许您修改lambda范围外定义的变量,但对这些变量所做的任何更改都不会扩展到初始变量: auto f1 = [=] () mutable { n += 4; return

如果我理解正确(我的源代码是《C++初级读本》第5版第395页),《代码》可变版本可以从
lambda
中修改捕获的变量。有两件事我不明白:

  • 这与通过引用捕获有什么不同?而且,如果通过引用捕获是下面发生的事情,那么
    mutable
    的目的是什么?只是一块糖

  • 如果
    mutable
    可以在每个变量的基础上应用,不是更有帮助吗


  • mutable
    允许您修改lambda范围外定义的变量,但对这些变量所做的任何更改都不会扩展到初始变量:

    auto f1 = [=] () mutable { n += 4; return n ; } ;
    auto f2 = [&] () { n += 4; return n ; } ;
    
    std::cout << f1 () << ' ' ;   // Call to f1, modify n inside f1
    std::cout << n << ' ' ;       // But not in main
    
    // 2nd call to f1, the value of n inside f1 is the value stored during the first call, 
    // so  8 (the output will be 8 + 4)
    std::cout << f1 () << ' ' ;   
    
    std::cout << f2 () << ' ' ;   // Call to f2, modify n inside f2
    std::cout << n << std::endl ; // And in main
    
    另一个区别是,使用“按值捕获”时,在计算lambda时捕获值,而不是在调用lambda时捕获值:

    int n = 4 ;
    auto f1 = [=] () mutable { return n ; } ; // lambda evaluated, value is 4
    auto f2 = [&] () { return n ; } ; // lambda evaluated, reference to n
    std::cout << f1 () << ' ' ; // Call to f1, captured value is 4
    std::cout << f2 () << ' ' ;
    n = 8 ;
    std::cout << f1 () << ' ' ; // Call to f1, captured value is still 4
    std::cout << f2 () << std::endl ; // Reference to n, so updated value printed
    
    最后一个(巨大的)区别是,一旦目标超出范围,引用捕获的变量就不可用:

    std::function <int ()> f (bool withref) {
        int n = 4 ;
        if (withref) {
            return [&] () { return n ; } ;
        }
        return [=] () { return n ; } ;
    }
    
    auto f1 = f (false) ;
    auto f2 = f (true) ;
    
    std::cout << f1 () << ' ' ;
    std::cout << f2 () << std::endl ; // Something will go wrong here...
    
    第二种行为尚未定义


    总结如下:

    • 使用
      mutable
      可以修改函数范围内由值捕获的变量,但由于在计算lambda时变量已复制到另一个内存位置,因此您只需修改变量的本地副本(您可以访问此副本,即使原始变量已消失)
    • 使用
      &
      不会创建原始变量的副本,允许您修改它(原始变量),但允许您在其«销毁»后访问此变量

    可变
    允许您修改lambda范围外定义的变量,但对这些变量所做的任何更改都不会扩展到初始变量:

    auto f1 = [=] () mutable { n += 4; return n ; } ;
    auto f2 = [&] () { n += 4; return n ; } ;
    
    std::cout << f1 () << ' ' ;   // Call to f1, modify n inside f1
    std::cout << n << ' ' ;       // But not in main
    
    // 2nd call to f1, the value of n inside f1 is the value stored during the first call, 
    // so  8 (the output will be 8 + 4)
    std::cout << f1 () << ' ' ;   
    
    std::cout << f2 () << ' ' ;   // Call to f2, modify n inside f2
    std::cout << n << std::endl ; // And in main
    
    另一个区别是,使用“按值捕获”时,在计算lambda时捕获值,而不是在调用lambda时捕获值:

    int n = 4 ;
    auto f1 = [=] () mutable { return n ; } ; // lambda evaluated, value is 4
    auto f2 = [&] () { return n ; } ; // lambda evaluated, reference to n
    std::cout << f1 () << ' ' ; // Call to f1, captured value is 4
    std::cout << f2 () << ' ' ;
    n = 8 ;
    std::cout << f1 () << ' ' ; // Call to f1, captured value is still 4
    std::cout << f2 () << std::endl ; // Reference to n, so updated value printed
    
    最后一个(巨大的)区别是,一旦目标超出范围,引用捕获的变量就不可用:

    std::function <int ()> f (bool withref) {
        int n = 4 ;
        if (withref) {
            return [&] () { return n ; } ;
        }
        return [=] () { return n ; } ;
    }
    
    auto f1 = f (false) ;
    auto f2 = f (true) ;
    
    std::cout << f1 () << ' ' ;
    std::cout << f2 () << std::endl ; // Something will go wrong here...
    
    第二种行为尚未定义


    总结如下:

    • 使用
      mutable
      可以修改函数范围内由值捕获的变量,但由于在计算lambda时变量已复制到另一个内存位置,因此您只需修改变量的本地副本(您可以访问此副本,即使原始变量已消失)
    • 使用
      &
      不会创建原始变量的副本,允许您修改它(原始变量),但允许您在其«销毁»后访问此变量


    1.这里有答案2.应该也很清楚,事后停止认为可变是(唯一的)与lambdas相关。@deviantfan我不明白你的意思。当一个对象是
    const
    时,它的方法可以修改
    mutable
    数据成员。但是在这里我选择声明哪些数据成员
    mutable
    ,而这里是all或none!@worldssender在你引用的帖子中解释了所有不同的选项工作(我知道
    lambda
    基本上是一个未命名类的对象,所以这对我来说并不新鲜)。但是,我没有看到这个问题的答案:为什么我要使用mutable而不是
    [&]
    ?我看起来缺少了一些非常基本的东西,但我不知道它是什么…@MeirGoldenberg,当使用
    [&]时
    您更改绑定lambda的作用域的变量。使用
    [=]mutable
    时,您首先复制变量,但可以在lambda中对其进行变异1。这里回答了2。应该也很清楚,事后停止认为mutable是(仅)与lambdas相关。@deviantfan我不明白你的意思。当一个对象是
    const
    时,它的方法可以修改
    mutable
    数据成员。但是在这里我选择声明哪些数据成员
    mutable
    ,而这里是all或none!@worldssender在你引用的帖子中解释了所有不同的选项工作(我知道
    lambda
    基本上是一个未命名类的对象,所以这对我来说并不新鲜)。但是,我没有看到这个问题的答案:为什么我要使用mutable而不是
    [&]
    ?我看起来缺少了一些非常基本的东西,但我不知道它是什么…@MeirGoldenberg,当使用
    [&]时
    您更改了绑定lambda的作用域的变量。使用
    [=]mutable
    时,您首先复制变量,但可以在lambda中对其进行变异谢谢!您真是一针见血!如果您使用
    f1
    增量
    n
    例如
    n+=4
    并调用
    f1()
    两次!@MeirGoldenberg是的,你是对的。它清楚地表明了一个事实,即有一个
    n
    的副本与
    f1
    相关(有一种带有初始值的
    静态变量)。我更新了我的答案。它不是一个静态变量。这是因为捕获的变量是
    lambda
    对象的数据成员。@MeirGoldenberg我没有说它是,只是行为(几乎)与执行
    [\n=n](){static int n=\n;n+=4;返回n;}
    没有
    mutable
    关键字。谢谢!你真是一针见血!如果你增加
    f1
    increment
    n
    例如
    n+=4
    并调用
    f1()
    两次!@MeirGoldenberg是的,你是对的,它清楚地表明了一个事实,即有一个
    n
    的副本与
    f1
    关联(有点像一个带有初始值的
    静态变量)。我更新了我的答案。它不是一个静态变量。这是捕获的变量是