理解可变捕获

Alw*_*ing 1 c++ lambda c++11

如果我理解正确(我的源代码是C++ Primer的第395页,第5版),mutable则可以从中修改捕获的变量lambda.我不明白的两件事:

  1. 这与通过引用捕获有何不同?并且,如果通过引用捕获正在发生的事情,那么目的是mutable什么?只是一个语法糖?

  2. 是否mutable可以在每个变量的基础上应用更有帮助?

Hol*_*olt 5

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

产量

8 4 12 8 8 
Run Code Online (Sandbox Code Playgroud)

另一个区别是,当您使用按值捕获时,将在计算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
Run Code Online (Sandbox Code Playgroud)

输出:

4 4 4 8 
Run Code Online (Sandbox Code Playgroud)

最后一个(巨大的)区别是,一旦目标超出范围,通过引用捕获的变量就不可用:

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...
Run Code Online (Sandbox Code Playgroud)

输出:

4 1639254944 
Run Code Online (Sandbox Code Playgroud)

第二种行为是未定义的.


总结一下:

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