mutable
does allow you to modify variable which are defined outside of the scope of the lambda, but any change you make to these variable is not spread to the initial variable:
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
Output
8 4 12 8 8
Another difference is that when you use capture by value, the value are captured when the lambda is evaluated, not when it is called:
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
Output:
4 4 4 8
One last (huge) difference is that variable captured by reference are not available once their target is out of scope:
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...
Output:
4 1639254944
The second behaviour is undefined.
To summarize:
- Using
mutable
allow you to modify variable captured by value inside the scope of your function, but since the variable have been copied to another memory location when the lambda has been evaluated, you are only modifying a local copy of the variable (and you have access to this copy, even when the original variable has vanished).
- Using
&
does not create a copy of the original variable(s), allowing you to modify it (the original one), but providing you to access this variable after its « destruction ».