Are static variables used in a lambda retained across calls of the function wherein the lambda is used? Or is the function object "created" again each function call?
Useless Example:
#include <iostream>
#include <vector>
#include <algorithm>
using std::cout;
void some_function()
{
std::vector<int> v = {0,1,2,3,4,5};
std::for_each( v.begin(), v.end(),
[](const int &i)
{
static int calls_to_cout = 0;
cout << "cout has been called " << calls_to_cout << " times.\n"
<< "\tCurrent int: " << i << "\n";
++calls_to_cout;
} );
}
int main()
{
some_function();
some_function();
}
What is the correct output for this program?
Is it dependent on the fact if the lambda captures local variables or not? (it will certainly change the underlying implementation of the function object, so it might have an influence) Is it an allowed behavioural inconsistency?
I'm not looking for: "My compiler outputs ...", this is too new a feature to trust current implementations IMHO. I know asking for Standard quotes seems to be popular since the world discovered such a thing exists, but still, I would like a decent source.
tl;dr version at the bottom.
§5.1.2 [expr.prim.lambda]
p1 lambda-expression:
lambda-introducer lambda-declaratoropt compound-statement
p3 The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed nonunion class type — called the closure type — whose properties are described below. This class type is not an aggregate (8.5.1). The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding lambda-expression. (My note: Functions have a block scope.)
p5 The closure type for a lambda-expression has a public inline function call operator [...]
p7 The lambda-expression’s compound-statement yields the function-body (8.4) of the function call operator [...]
Since the compound-statement is directly taken as the function call operator's body, and the closure type is defined in the smallest (innermost) scope, it's the same as writing the following:
void some_function()
{
struct /*unnamed unique*/{
inline void operator()(int const& i) const{
static int calls_to_cout = 0;
cout << "cout has been called " << calls_to_cout << " times.\n"
<< "\tCurrent int: " << i << "\n";
++calls_to_cout;
}
} lambda;
std::vector<int> v = {0,1,2,3,4,5};
std::for_each( v.begin(), v.end(), lambda);
}
Which is legal C++, functions are allowed to have static local variables.
§3.7.1 [basic.stc.static]
p1 All variables which do not have dynamic storage duration, do not have thread storage duration, and are not local have static storage duration. The storage for these entities shall last for the duration of the program.
p3 The keyword static can be used to declare a local variable with static storage duration. [...]
§6.7 [stmt.dcl] p4
(This deals with initialization of variables with static storage duration in a block scope.)
[...] Otherwise such a variable is initialized the first time control passes through its declaration; [...]
To reiterate:
The type of a lambda expression is created in the innermost scope.
It is not created anew for each function call (that wouldn't make sense, since the enclosing function body would be as my example above).
It obeys (nearly) all the rules of normal classes / structs (just some stuff about this is different), since it is a non-union class type.
Now that we have assured that for every function call, the closure type is the same, we can safely say that the static local variable is also the same; it's initialized the first time the function call operator is invoked and lives until the end of the program.
The static variable should behave just like it would in a function body. However there's little reason to use one, since a lambda object can have member variables.
In the following, calls_to_cout is captured by value, which gives the lambda a member variable with the same name, initialized to the current value of calls_to_cout. This member variable retains its value across calls but is local to the lambda object, so any copies of the lambda will get their own calls_to_cout member variable instead of all sharing one static variable. This is much safer and better.
(and since lambdas are const by default and this lambda modifies calls_to_cout it must be declared as mutable.)
void some_function()
{
vector<int> v = {0,1,2,3,4,5};
int calls_to_cout = 0;
for_each(v.begin(), v.end(),[calls_to_cout](const int &i) mutable
{
cout << "cout has been called " << calls_to_cout << " times.\n"
<< "\tCurrent int: " << i << "\n";
++calls_to_cout;
});
}
If you do want a single variable to be shared between instances of the lambda you're still better off using captures. Just capture some kind of reference to the variable. For example here's a function that returns a pair of functions which share a reference to a single variable, and each function performs its own operation on that shared variable when called.
std::tuple<std::function<int()>,std::function<void()>>
make_incr_reset_pair() {
std::shared_ptr<int> i = std::make_shared<int>(0);
return std::make_tuple(
[=]() { return ++*i; },
[=]() { *i = 0; });
}
int main() {
std::function<int()> increment;
std::function<void()> reset;
std::tie(increment,reset) = make_incr_reset_pair();
std::cout << increment() << '\n';
std::cout << increment() << '\n';
std::cout << increment() << '\n';
reset();
std::cout << increment() << '\n';
A static can be constructed in the capture:-
auto v = vector<int>(99);
generate(v.begin(), v.end(), [x = int(1)] () mutable { return x++; });
The lambda can made by another lambda
auto inc = [y=int(1)] () mutable {
++y; // has to be separate, it doesn't like ++y inside the []
return [y, x = int(1)] () mutable { return y+x++; };
};
generate(v.begin(), v.end(), inc());
Here, y can also be captured by reference as long as inc lasts longer.
There are two ways to use states with lambdas.
Defining the variable as static in the lambda: the variable is
persistent over lambda calls and lambda instantiations.
Defining the variable in the lambda capture and mark the lambda as mutable: the variable is persistent over lambda calls but it is reset at every and lambda instantiations
The following code illustrate the difference:
void foo() {
auto f = [k=int(1)]() mutable { cout << k++ << "\n";}; // define k in the capture
f();
f();
}
void bar() {
auto f = []() { static int k = 1; cout << k++ << "\n";}; // define k as static
f();
f();
}
void test() {
foo();
foo(); // k is reset every time the lambda is created
bar();
bar(); // k is persistent through lambda instantiations
return 0;
}
I do not have a copy of the final standard, and the draft does not appear to address the issue explicitly (see section 5.1.2, starting on page 87 of the PDF). But it does say that a lambda expression evaluates to a single object of closure type, which may be invoked repeatedly. That being so, I believe the standard requires that static variables be initialized once and only once, just as though you'd written out the class, operator(), and variable capture by hand.
But as you say, this is a new feature; at least for now you're stuck with whatever your implementation does, no matter what the standard says. It's better style to explicitly capture a variable in the enclosing scope anyway.
The short answer: static variables declared inside of a lambda work the same as function static variables in the enclosing scope that were automatically captured (by reference).
In this case, even though the lambda object is returned twice, the values persist:
auto make_sum()
{
static int sum = 0;
static int count = 0;
//Wrong, since these do not have static duration, they are implicitly captured
//return [&sum, &count](const int&i){
return [](const int&i){
sum += i;
++count;
cout << "sum: "<< sum << " count: " << count << endl;
};
}
int main(int argc, const char * argv[]) {
vector<int> v = {0,1,1,2,3,5,8,13};
for_each(v.begin(), v.end(), make_sum());
for_each(v.begin(), v.end(), make_sum());
return 0;
}
vs:
auto make_sum()
{
return [](const int&i){
//Now they are inside the lambda
static int sum = 0;
static int count = 0;
sum += i;
++count;
cout << "sum: "<< sum << " count: " << count << endl;
};
}
int main(int argc, const char * argv[]) {
vector<int> v = {0,1,1,2,3,5,8,13};
for_each(v.begin(), v.end(), make_sum());
for_each(v.begin(), v.end(), make_sum());
return 0;
}
Both give the same output:
sum: 0 count: 1
sum: 1 count: 2
sum: 2 count: 3
sum: 4 count: 4
sum: 7 count: 5
sum: 12 count: 6
sum: 20 count: 7
sum: 33 count: 8
sum: 33 count: 9
sum: 34 count: 10
sum: 35 count: 11
sum: 37 count: 12
sum: 40 count: 13
sum: 45 count: 14
sum: 53 count: 15
sum: 66 count: 16
Related
I am not able to understand the output of the below code:-
#include <iostream>
using namespace std;
template <typename T>
void fun(const T&x){
static int count = 0;
cout << "x = " << x << " count = " << count << endl;
++count;
return;
}
int main(){
fun(1);
fun('A');
fun(1.1);
fun(2.2);
return 0;
}
Output:-
x = 1 count = 0
x = A count = 0
x = 1.1 count = 0
x = 2.2 count = 1
If value of static variable count is being reassigned to 0 whenever the function is called, then why its coming 1 when the function is being called fourth time.
And another thing , can we not pass "T x" directly instead of "const T&x"?
When a template gets instantiated, with explicit or deduced template parameters, it's as if a completely new, discrete, class or function gets declared. In your case, this template ends up creating three functions:
void fun<int>(const int &x)
void fun<char>(const char &x)
void fun<double>(const double &x)
It's important to understand that each one of these is a separate, standalone function, with its own static count variable. Because it's static, it gets initialized once, and its value is preserved across function calls. That's how static variables work in functions.
The shown code calls the first two once, and the third one twice. Those are the results you are seeing (the 2nd call to the third function incremented the same static count again).
Templates in C++ aren't generic functions like they are in Java. They're more like cookie cutters that make a new type-specific function for each type used to instantiate them. Your code is basically equivalent to this:
#include <iostream>
using namespace std;
void fun_int(const int&x){
static int count = 0;
cout << "x = " << x << " count = " << count << endl;
++count;
return;
}
void fun_char(const char&x){
static int count = 0;
cout << "x = " << x << " count = " << count << endl;
++count;
return;
}
void fun_double(const double&x){
static int count = 0;
cout << "x = " << x << " count = " << count << endl;
++count;
return;
}
int main(){
fun_int(1);
fun_char('A');
fun_double(1.1);
fun_double(2.2);
return 0;
}
And now it's obvious that you don't just have one static variable, but rather three different ones in different functions that just happen to have the same name.
If value of static variable count is being reassigned to 0 whenever the function is called...
That's where you're wrong. A static variable with an initializer (irrespective of its scope) is set to the value of the initializer once and once only. For static variables declared globally (in file scope), that initialization will be at program start-up; for static data declared in functions (as yours are), that initialization is deferred to the first time the function's code is executed.
Your code defines three different overloads of fun, each of which has its own copy of the local count variable. When the overload with the double argument is called the second time, the count variable will not be reinitialized – just incremented.
From this Draft C++17 Standard:
6.8.3.2 Static initialization [basic.start.static]
1 Variables with static storage duration are initialized as a consequence of program
initiation. …
and, for locally-declared static variables, we have this:
9.7 Declaration statement [stmt.dcl]
…
4 Dynamic initialization of a block-scope variable
with static storage duration or thread storage
duration is performed the first time control passes through its
declaration; such a variable is considered initialized upon the completion of its initialization. …
Short example:
#include <iostream>
int main()
{
int n;
[&](){n = 10;}(); // OK
[=]() mutable {n = 20;}(); // OK
// [=](){n = 10;}(); // Error: a by-value capture cannot be modified in a non-mutable lambda
std::cout << n << "\n"; // "10"
}
The question: Why do we need the mutable keyword? It's quite different from traditional parameter passing to named functions. What's the rationale behind?
I was under the impression that the whole point of capture-by-value is to allow the user to change the temporary -- otherwise I'm almost always better off using capture-by-reference, aren't I?
Any enlightenments?
(I'm using MSVC2010 by the way. AFAIK this should be standard)
It requires mutable because by default, a function object should produce the same result every time it's called. This is the difference between an object orientated function and a function using a global variable, effectively.
Your code is almost equivalent to this:
#include <iostream>
class unnamed1
{
int& n;
public:
unnamed1(int& N) : n(N) {}
/* OK. Your this is const but you don't modify the "n" reference,
but the value pointed by it. You wouldn't be able to modify a reference
anyway even if your operator() was mutable. When you assign a reference
it will always point to the same var.
*/
void operator()() const {n = 10;}
};
class unnamed2
{
int n;
public:
unnamed2(int N) : n(N) {}
/* OK. Your this pointer is not const (since your operator() is "mutable" instead of const).
So you can modify the "n" member. */
void operator()() {n = 20;}
};
class unnamed3
{
int n;
public:
unnamed3(int N) : n(N) {}
/* BAD. Your this is const so you can't modify the "n" member. */
void operator()() const {n = 10;}
};
int main()
{
int n;
unnamed1 u1(n); u1(); // OK
unnamed2 u2(n); u2(); // OK
//unnamed3 u3(n); u3(); // Error
std::cout << n << "\n"; // "10"
}
So you could think of lambdas as generating a class with operator() that defaults to const unless you say that it is mutable.
You can also think of all the variables captured inside [] (explicitly or implicitly) as members of that class: copies of the objects for [=] or references to the objects for [&]. They are initialized when you declare your lambda as if there was a hidden constructor.
I was under the impression that the whole point of capture-by-value is to allow the user to change the temporary -- otherwise I'm almost always better off using capture-by-reference, aren't I?
The question is, is it "almost"? A frequent use-case appears to be to return or pass lambdas:
void registerCallback(std::function<void()> f) { /* ... */ }
void doSomething() {
std::string name = receiveName();
registerCallback([name]{ /* do something with name */ });
}
I think that mutable isn't a case of "almost". I consider "capture-by-value" like "allow me to use its value after the captured entity dies" rather than "allow me to change a copy of it". But perhaps this can be argued.
You have to understand what capture means! it's capturing not argument passing! let's look at some code samples:
int main()
{
using namespace std;
int x = 5;
int y;
auto lamb = [x]() {return x + 5; };
y= lamb();
cout << y<<","<< x << endl; //outputs 10,5
x = 20;
y = lamb();
cout << y << "," << x << endl; //output 10,20
}
As you can see even though x has been changed to 20 the lambda is still returning 10 ( x is still 5 inside the lambda)
Changing x inside the lambda means changing the lambda itself at each call (the lambda is mutating at each call). To enforce correctness the standard introduced the mutable keyword. By specifying a lambda as mutable you are saying that each call to the lambda could cause a change in the lambda itself. Let see another example:
int main()
{
using namespace std;
int x = 5;
int y;
auto lamb = [x]() mutable {return x++ + 5; };
y= lamb();
cout << y<<","<< x << endl; //outputs 10,5
x = 20;
y = lamb();
cout << y << "," << x << endl; //outputs 11,20
}
The above example shows that by making the lambda mutable, changing x inside the lambda "mutates" the lambda at each call with a new value of x that has no thing to do with the actual value of x in the main function
FWIW, Herb Sutter, a well-known member of the C++ standardization committee, provides a different answer to that question in Lambda Correctness and Usability Issues:
Consider this straw man example, where the programmer captures a local variable by
value and tries to modify the
captured value (which is a member variable of the lambda object):
int val = 0;
auto x = [=](item e) // look ma, [=] means explicit copy
{ use(e,++val); }; // error: count is const, need ‘mutable’
auto y = [val](item e) // darnit, I really can’t get more explicit
{ use(e,++val); }; // same error: count is const, need ‘mutable’
This feature appears to have been added out of a concern that the user
might not realize he got a copy, and in particular that since lambdas
are copyable he might be changing a different lambda’s copy.
His paper is about why this should be changed in C++14. It is short, well written, worth reading if you want to know "what's on [committee member] minds" with regards to this particular feature.
You need to think what is the closure type of your Lambda function. Every time you declare a Lambda expression, the compiler creates a closure type, which is nothing less than an unnamed class declaration with attributes (environment where the Lambda expression where declared) and the function call ::operator() implemented. When you capture a variable using copy-by-value, the compiler will create a new const attribute in the closure type, so you can't change it inside the Lambda expression because it is a "read-only" attribute, that's the reason they call it a "closure", because in some way, you are closing your Lambda expression by copying the variables from upper scope into the Lambda scope. When you use the keyword mutable, the captured entity will became a non-const attribute of your closure type. This is what causes the changes done in the mutable variable captured by value, to not be propagated to upper scope, but keep inside the stateful Lambda.
Always try to imagine the resulting closure type of your Lambda expression, that helped me a lot, and I hope it can help you too.
See this draft, under 5.1.2 [expr.prim.lambda], subclause 5:
The closure type for a lambda-expression has a public inline function call operator (13.5.4) whose parameters
and return type are described by the lambda-expression’s parameter-declaration-clause and trailingreturn-
type respectively. This function call operator is declared const (9.3.1) if and only if the lambdaexpression’s
parameter-declaration-clause is not followed by mutable.
Edit on litb's comment:
Maybe they thought of capture-by-value so that outside changes to the variables aren't reflected inside the lambda? References work both ways, so that's my explanation. Don't know if it's any good though.
Edit on kizzx2's comment:
The most times when a lambda is to be used is as a functor for algorithms. The default constness lets it be used in a constant environment, just like normal const-qualified functions can be used there, but non-const-qualified ones can't. Maybe they just thought to make it more intuitive for those cases, who know what goes on in their mind. :)
I was under the impression that the
whole point of capture-by-value is to
allow the user to change the temporary
-- otherwise I'm almost always better off using capture-by-reference, aren't
I?
n is not a temporary. n is a member of the lambda-function-object that you create with the lambda expression. The default expectation is that calling your lambda does not modify its state, therefore it is const to prevent you from accidentally modifying n.
To extend Puppy's answer, lambda functions are intended to be pure functions. That means every call given a unique input set always returns the same output. Let's define input as the set of all arguments plus all captured variables when the lambda is called.
In pure functions output solely depends on input and not on some internal state. Therefore any lambda function, if pure, does not need to change its state and is therefore immutable.
When a lambda captures by reference, writing on captured variables is a strain on the concept of pure function, because all a pure function should do is return an output, though the lambda does not certainly mutate because the writing happens to external variables. Even in this case a correct usage implies that if the lambda is called with the same input again, the output will be the same everytime, despite these side effects on by-ref variables. Such side effects are just ways to return some additional input (e.g. update a counter) and could be reformulated into a pure function, for example returning a tuple instead of a single value.
I also was wondering about it and the simplest explanation why [=] requires explicit mutable is in this example:
int main()
{
int x {1};
auto lbd = [=]() mutable { return x += 5; };
printf("call1:%d\n", lbd());
printf("call2:%d\n", lbd());
return 0;
}
Output:
call1:6
call2:11
By words:
You can see that the x value is different at the second call (1 for the call1 and 6 for the call2).
A lambda object keeps a captured variable by value (has its own
copy) in case of [=].
The lambda can be called several times.
And in general case we have to have the same value of the captured variable to have the same predictable behavior of the lambda based on the known captured value, not updated during the lambda work. That's why the default behavior assumed const (to predict changes of the lambda object members) and when a user is aware of consequences he takes this responsibility on himself with mutable.
Same with capturing by value. For my example:
auto lbd = [x]() mutable { return x += 5; };
There is now a proposal to alleviate the need for mutable in lambda declarations: n3424
You might see the difference, if you check 3 different use cases of lambda:
Capturing an argument by value
Capturing an argument by value with 'mutable' keyword
Capturing an argument by reference
case 1:
When you capture an argument by value, a few things happen:
You are not allowed to modify the argument inside the lambda
The value of the argument remains the same, whenever the lambda is
called, not matter what will be the argument value at the time the lambda is called.
so for example:
{
int x = 100;
auto lambda1 = [x](){
// x += 2; // compile time error. not allowed
// to modify an argument that is captured by value
return x * 2;
};
cout << lambda1() << endl; // 100 * 2 = 200
cout << "x: " << x << endl; // 100
x = 300;
cout << lambda1() << endl; // in the lambda, x remain 100. 100 * 2 = 200
cout << "x: " << x << endl; // 300
}
Output:
200
x: 100
200
x: 300
case 2:
Here, when you capture an argument by value and use the 'mutable' keyword, similar to the first case, you create a "copy" of this argument. This "copy" lives in the "world" of the lambda, but now, you can actually modify the argument within the lambda-world, so its value is changed, and saved and it can be referred to, in the future calls of this lambda. Again, the outside "life" of the argument might be totally different (value wise):
{
int x = 100;
auto lambda2 = [x]() mutable {
x += 2; // when capture by value, modify the argument is
// allowed when mutable is used.
return x;
};
cout << lambda2() << endl; // 100 + 2 = 102
cout << "x: " << x << endl; // in the outside world - x remains 100
x = 200;
cout << lambda2() << endl; // 104, as the 102 is saved in the lambda world.
cout << "x: " << x << endl; // 200
}
Output:
102
x: 100
104
x: 200
case 3:
This is the easiest case, as no more 2 lives of x. Now there is only one value for x and it's shared between the outside world and the lambda world.
{
int x = 100;
auto lambda3 = [&x]() mutable {
x += 10; // modify the argument, is allowed when mutable is used.
return x;
};
cout << lambda3() << endl; // 110
cout << "x: " << x << endl; // 110
x = 400;
cout << lambda3() << endl; // 410.
cout << "x: " << x << endl; // 410
}
Output:
110
x: 110
410
x: 410
Short example:
#include <iostream>
int main()
{
int n;
[&](){n = 10;}(); // OK
[=]() mutable {n = 20;}(); // OK
// [=](){n = 10;}(); // Error: a by-value capture cannot be modified in a non-mutable lambda
std::cout << n << "\n"; // "10"
}
The question: Why do we need the mutable keyword? It's quite different from traditional parameter passing to named functions. What's the rationale behind?
I was under the impression that the whole point of capture-by-value is to allow the user to change the temporary -- otherwise I'm almost always better off using capture-by-reference, aren't I?
Any enlightenments?
(I'm using MSVC2010 by the way. AFAIK this should be standard)
It requires mutable because by default, a function object should produce the same result every time it's called. This is the difference between an object orientated function and a function using a global variable, effectively.
Your code is almost equivalent to this:
#include <iostream>
class unnamed1
{
int& n;
public:
unnamed1(int& N) : n(N) {}
/* OK. Your this is const but you don't modify the "n" reference,
but the value pointed by it. You wouldn't be able to modify a reference
anyway even if your operator() was mutable. When you assign a reference
it will always point to the same var.
*/
void operator()() const {n = 10;}
};
class unnamed2
{
int n;
public:
unnamed2(int N) : n(N) {}
/* OK. Your this pointer is not const (since your operator() is "mutable" instead of const).
So you can modify the "n" member. */
void operator()() {n = 20;}
};
class unnamed3
{
int n;
public:
unnamed3(int N) : n(N) {}
/* BAD. Your this is const so you can't modify the "n" member. */
void operator()() const {n = 10;}
};
int main()
{
int n;
unnamed1 u1(n); u1(); // OK
unnamed2 u2(n); u2(); // OK
//unnamed3 u3(n); u3(); // Error
std::cout << n << "\n"; // "10"
}
So you could think of lambdas as generating a class with operator() that defaults to const unless you say that it is mutable.
You can also think of all the variables captured inside [] (explicitly or implicitly) as members of that class: copies of the objects for [=] or references to the objects for [&]. They are initialized when you declare your lambda as if there was a hidden constructor.
I was under the impression that the whole point of capture-by-value is to allow the user to change the temporary -- otherwise I'm almost always better off using capture-by-reference, aren't I?
The question is, is it "almost"? A frequent use-case appears to be to return or pass lambdas:
void registerCallback(std::function<void()> f) { /* ... */ }
void doSomething() {
std::string name = receiveName();
registerCallback([name]{ /* do something with name */ });
}
I think that mutable isn't a case of "almost". I consider "capture-by-value" like "allow me to use its value after the captured entity dies" rather than "allow me to change a copy of it". But perhaps this can be argued.
You have to understand what capture means! it's capturing not argument passing! let's look at some code samples:
int main()
{
using namespace std;
int x = 5;
int y;
auto lamb = [x]() {return x + 5; };
y= lamb();
cout << y<<","<< x << endl; //outputs 10,5
x = 20;
y = lamb();
cout << y << "," << x << endl; //output 10,20
}
As you can see even though x has been changed to 20 the lambda is still returning 10 ( x is still 5 inside the lambda)
Changing x inside the lambda means changing the lambda itself at each call (the lambda is mutating at each call). To enforce correctness the standard introduced the mutable keyword. By specifying a lambda as mutable you are saying that each call to the lambda could cause a change in the lambda itself. Let see another example:
int main()
{
using namespace std;
int x = 5;
int y;
auto lamb = [x]() mutable {return x++ + 5; };
y= lamb();
cout << y<<","<< x << endl; //outputs 10,5
x = 20;
y = lamb();
cout << y << "," << x << endl; //outputs 11,20
}
The above example shows that by making the lambda mutable, changing x inside the lambda "mutates" the lambda at each call with a new value of x that has no thing to do with the actual value of x in the main function
FWIW, Herb Sutter, a well-known member of the C++ standardization committee, provides a different answer to that question in Lambda Correctness and Usability Issues:
Consider this straw man example, where the programmer captures a local variable by
value and tries to modify the
captured value (which is a member variable of the lambda object):
int val = 0;
auto x = [=](item e) // look ma, [=] means explicit copy
{ use(e,++val); }; // error: count is const, need ‘mutable’
auto y = [val](item e) // darnit, I really can’t get more explicit
{ use(e,++val); }; // same error: count is const, need ‘mutable’
This feature appears to have been added out of a concern that the user
might not realize he got a copy, and in particular that since lambdas
are copyable he might be changing a different lambda’s copy.
His paper is about why this should be changed in C++14. It is short, well written, worth reading if you want to know "what's on [committee member] minds" with regards to this particular feature.
You need to think what is the closure type of your Lambda function. Every time you declare a Lambda expression, the compiler creates a closure type, which is nothing less than an unnamed class declaration with attributes (environment where the Lambda expression where declared) and the function call ::operator() implemented. When you capture a variable using copy-by-value, the compiler will create a new const attribute in the closure type, so you can't change it inside the Lambda expression because it is a "read-only" attribute, that's the reason they call it a "closure", because in some way, you are closing your Lambda expression by copying the variables from upper scope into the Lambda scope. When you use the keyword mutable, the captured entity will became a non-const attribute of your closure type. This is what causes the changes done in the mutable variable captured by value, to not be propagated to upper scope, but keep inside the stateful Lambda.
Always try to imagine the resulting closure type of your Lambda expression, that helped me a lot, and I hope it can help you too.
See this draft, under 5.1.2 [expr.prim.lambda], subclause 5:
The closure type for a lambda-expression has a public inline function call operator (13.5.4) whose parameters
and return type are described by the lambda-expression’s parameter-declaration-clause and trailingreturn-
type respectively. This function call operator is declared const (9.3.1) if and only if the lambdaexpression’s
parameter-declaration-clause is not followed by mutable.
Edit on litb's comment:
Maybe they thought of capture-by-value so that outside changes to the variables aren't reflected inside the lambda? References work both ways, so that's my explanation. Don't know if it's any good though.
Edit on kizzx2's comment:
The most times when a lambda is to be used is as a functor for algorithms. The default constness lets it be used in a constant environment, just like normal const-qualified functions can be used there, but non-const-qualified ones can't. Maybe they just thought to make it more intuitive for those cases, who know what goes on in their mind. :)
I was under the impression that the
whole point of capture-by-value is to
allow the user to change the temporary
-- otherwise I'm almost always better off using capture-by-reference, aren't
I?
n is not a temporary. n is a member of the lambda-function-object that you create with the lambda expression. The default expectation is that calling your lambda does not modify its state, therefore it is const to prevent you from accidentally modifying n.
To extend Puppy's answer, lambda functions are intended to be pure functions. That means every call given a unique input set always returns the same output. Let's define input as the set of all arguments plus all captured variables when the lambda is called.
In pure functions output solely depends on input and not on some internal state. Therefore any lambda function, if pure, does not need to change its state and is therefore immutable.
When a lambda captures by reference, writing on captured variables is a strain on the concept of pure function, because all a pure function should do is return an output, though the lambda does not certainly mutate because the writing happens to external variables. Even in this case a correct usage implies that if the lambda is called with the same input again, the output will be the same everytime, despite these side effects on by-ref variables. Such side effects are just ways to return some additional input (e.g. update a counter) and could be reformulated into a pure function, for example returning a tuple instead of a single value.
I also was wondering about it and the simplest explanation why [=] requires explicit mutable is in this example:
int main()
{
int x {1};
auto lbd = [=]() mutable { return x += 5; };
printf("call1:%d\n", lbd());
printf("call2:%d\n", lbd());
return 0;
}
Output:
call1:6
call2:11
By words:
You can see that the x value is different at the second call (1 for the call1 and 6 for the call2).
A lambda object keeps a captured variable by value (has its own
copy) in case of [=].
The lambda can be called several times.
And in general case we have to have the same value of the captured variable to have the same predictable behavior of the lambda based on the known captured value, not updated during the lambda work. That's why the default behavior assumed const (to predict changes of the lambda object members) and when a user is aware of consequences he takes this responsibility on himself with mutable.
Same with capturing by value. For my example:
auto lbd = [x]() mutable { return x += 5; };
There is now a proposal to alleviate the need for mutable in lambda declarations: n3424
You might see the difference, if you check 3 different use cases of lambda:
Capturing an argument by value
Capturing an argument by value with 'mutable' keyword
Capturing an argument by reference
case 1:
When you capture an argument by value, a few things happen:
You are not allowed to modify the argument inside the lambda
The value of the argument remains the same, whenever the lambda is
called, not matter what will be the argument value at the time the lambda is called.
so for example:
{
int x = 100;
auto lambda1 = [x](){
// x += 2; // compile time error. not allowed
// to modify an argument that is captured by value
return x * 2;
};
cout << lambda1() << endl; // 100 * 2 = 200
cout << "x: " << x << endl; // 100
x = 300;
cout << lambda1() << endl; // in the lambda, x remain 100. 100 * 2 = 200
cout << "x: " << x << endl; // 300
}
Output:
200
x: 100
200
x: 300
case 2:
Here, when you capture an argument by value and use the 'mutable' keyword, similar to the first case, you create a "copy" of this argument. This "copy" lives in the "world" of the lambda, but now, you can actually modify the argument within the lambda-world, so its value is changed, and saved and it can be referred to, in the future calls of this lambda. Again, the outside "life" of the argument might be totally different (value wise):
{
int x = 100;
auto lambda2 = [x]() mutable {
x += 2; // when capture by value, modify the argument is
// allowed when mutable is used.
return x;
};
cout << lambda2() << endl; // 100 + 2 = 102
cout << "x: " << x << endl; // in the outside world - x remains 100
x = 200;
cout << lambda2() << endl; // 104, as the 102 is saved in the lambda world.
cout << "x: " << x << endl; // 200
}
Output:
102
x: 100
104
x: 200
case 3:
This is the easiest case, as no more 2 lives of x. Now there is only one value for x and it's shared between the outside world and the lambda world.
{
int x = 100;
auto lambda3 = [&x]() mutable {
x += 10; // modify the argument, is allowed when mutable is used.
return x;
};
cout << lambda3() << endl; // 110
cout << "x: " << x << endl; // 110
x = 400;
cout << lambda3() << endl; // 410.
cout << "x: " << x << endl; // 410
}
Output:
110
x: 110
410
x: 410
this piece of code is not something unknown to JS developers
function get_counter()
{
return (
function() {
var c = 0;
return function() { return ++c; };
})();
}
it basically creates a which creates different enumerators. So I was wondering if same thing can be done in C++11 with new lambda semantics? I ended up writing this piece of C++ which unfortunately does not compile!
int main()
{
int c;
auto a = [](){
int c = 0;
return [&](){
cout << c++;
};
};
return 0;
}
so I was wondering if there is a workaround to get it compiled and if there is how can compiler make this code run correctly? I mean it has to create separate enumerators but it should also collect garbage (unused c variables).
by the way I'm using VS2012 compiler and it generates this error:
Error 2 error C2440: 'return' : cannot convert from 'main::<lambda_10d109c73135f5c106ecbfa8ff6f4b6b>::()::<lambda_019decbc8d6cd29488ffec96883efe2a>' to 'void (__cdecl *)(void)' c:\users\ali\documents\visual studio 2012\projects\test\test\main.cpp 25 1 Test
Your code has a bug in that it contains a dangling reference; the c reference will refer to the local variable in the outer lambda, which will be destroyed when the outer lambda returns.
You should write it using a mutable by-value lambda capture:
auto a = []() {
int c = 0;
return [=]() mutable {
cout << c++;
};
};
This relies on a post-standard extension to allow multiple statements in a return-type-deducing lambda; Is there a reason on not allowing lambdas to deduce the return type if it contains more than one statement? The easiest way to fix it is to supply a parameter so that the lambda contains only a single statement:
auto a = [](int c) {
return [=]() mutable {
cout << c++;
};
};
Unfortunately default parameters aren't allowed in lambdas, so you'd have to call this as a(0). Alternatively at the cost of readability you could use a nested lambda call:
auto a = []() {
return ([](int c) {
return [=]() mutable {
cout << c++;
};
})(0);
};
The way this works is that when a executes the inner lambda copies all the referenced variables into an instance of its closure type, which here would be something like:
struct inner_lambda {
int c;
void operator()() { cout << c++; }
};
The instance of the closure type is then returned by the outer lambda, and can be invoked and will modify its copy of c when called.
Overall, your (fixed) code is translated to:
struct outer_lambda {
// no closure
struct inner_lambda {
int c; // by-value capture
// non-const because "mutable"
void operator()() { cout << c++; }
}
// const because non-"mutable"
inner_lambda operator()(int c) const {
return inner_lambda{c};
}
};
If you left c as a by-reference capture, this would be:
struct outer_lambda {
// no closure
struct inner_lambda {
int &c; // by-reference capture
void operator()() const { cout << c++; } // const, but can modify c
}
inner_lambda operator()(int c) const {
return inner_lambda{c};
}
};
Here inner_lambda::c is a dangling reference to the local parameter variable c.
It's a natural limitation of C++ that a lambda which captures by reference can't use the captured variable any more, once the variable no longer exists. So even if you get it to compile, you can't return this lambda from the function in which it appears (that also happens to be a lambda, but that's irrelevant), because the automatic variable c is destroyed on return.
I think the code you need is:
return [=]() mutable {
cout << c++;
};
I haven't tested it and I don't know what compiler versions support it, but that's a capture-by-value, with mutable to say that the captured value can be modified by the lambda.
So each time you call a you get a different counter with its own count starting from 0. Each time you call that counter, it increments its own copy of c. As far as I understand Javascript (not far), that's what you want.
I think the problem is that the compiler cannot deduce the return type of the outer lambda (that assigned to a) because it consists of more than a simple one line return. But unfortunately there is also no way to explicitly state the type of the inner lambda. So you will have to return a std::function, which comes with some additional overhead:
int main()
{
int c;
auto a = []() -> std::function<void()> {
int c = 0;
return [=]() mutable {
std::cout << c++;
};
};
return 0;
}
And of course you have to capture by-value, like Steve already explained in his answer.
EDIT: As to why the exact error is that it cannot convert the returned inner lambda to void(*)() (pointer to void() function), I only have some guesses because I don't have much insight into their lambda implementation, which I'm not sure is that stable or standard-conformant at all.
But I think VC at least tries to deduce the return type of the inner lambda and realizes that it returns a callable. But then it somehow incorrectly assumes this inner lambda to not capture (or they are not able to determine the inner lambda's type), so they just make the outer lambda return a simple function pointer, which would indeed work if the inner lambda wouldn't capture anything.
EDIT: And like ecatmur states in his comment, returning a std::function is even neccessary when making an actual get_counter function (instead of a lambda), since normal functions don't have any automatic return type deduction.
The first thing you should know is that even if you get the syntax to compile, the semantics are different. In C++ lambdas that capture by reference capture just a plain reference, that will not extend the lifetime of the object bound by that reference. That is, the lifetime of c is bound to the lifetime of the enclosing lambda:
int main()
{
int c;
auto a = [](){
int c = 0;
return [&](){
return ++c;
};
}(); // Note: added () as in the JS case
std::cout << a() << a();
return 0;
}
After adding the missing () so that the external lambda is evaluated, your problem is that the c that is held by reference in the returned lambda is no longer valid after the evaluation of the full expression.
That being said, it is not too complex to make that work at the cost of an extra dynamic allocation (which would be the equivalent of the JS case):
int main()
{
int c;
auto a = [](){
std::shared_ptr<int> c = std::make_shared<int>(0);
return [=](){
return ++(*c);
};
}(); // Note: added () as in the JS case
std::cout << a() << a();
return 0;
}
That should compile and work as expected. Whenever the internal lambda is released (a goes out of scope) the counter will be freed from memory.
This works on g++ 4.7
#include <iostream>
#include <functional>
std::function<int()> make_counter() {
return []()->std::function<int()> {
int c=0;
return [=]() mutable ->int {
return c++ ;
};
}();
}
int main(int argc, char * argv[]) {
int i = 1;
auto count1= make_counter();
auto count2= make_counter();
std::cout << "count1=" << count1() << std::endl;
std::cout << "count1=" << count1() << std::endl;
std::cout << "count2=" << count2() << std::endl;
std::cout << "count1=" << count1() << std::endl;
std::cout << "count2=" << count2() << std::endl;
return 0;
}
Valgrind doesn't complain about this at all. Every time I call make_counter, valgrind reports an additional allocation and free, so I assume the lambda meta programming code is inserting the allocation code for the memory for variable c (I guess I can check the debugger). I wonder if this is Cxx11 compliant or just g++ specific. Clang 3.0 will not compile this because it doesn't have std::function (maybe I can try using boost function).
I know this is late, but in C++14 and later you can now initiliaze a lambda capture, leading to more simple code:
auto a = []() {
return [c=0]() mutable {
cout << c++;
};
};
Short example:
#include <iostream>
int main()
{
int n;
[&](){n = 10;}(); // OK
[=]() mutable {n = 20;}(); // OK
// [=](){n = 10;}(); // Error: a by-value capture cannot be modified in a non-mutable lambda
std::cout << n << "\n"; // "10"
}
The question: Why do we need the mutable keyword? It's quite different from traditional parameter passing to named functions. What's the rationale behind?
I was under the impression that the whole point of capture-by-value is to allow the user to change the temporary -- otherwise I'm almost always better off using capture-by-reference, aren't I?
Any enlightenments?
(I'm using MSVC2010 by the way. AFAIK this should be standard)
It requires mutable because by default, a function object should produce the same result every time it's called. This is the difference between an object orientated function and a function using a global variable, effectively.
Your code is almost equivalent to this:
#include <iostream>
class unnamed1
{
int& n;
public:
unnamed1(int& N) : n(N) {}
/* OK. Your this is const but you don't modify the "n" reference,
but the value pointed by it. You wouldn't be able to modify a reference
anyway even if your operator() was mutable. When you assign a reference
it will always point to the same var.
*/
void operator()() const {n = 10;}
};
class unnamed2
{
int n;
public:
unnamed2(int N) : n(N) {}
/* OK. Your this pointer is not const (since your operator() is "mutable" instead of const).
So you can modify the "n" member. */
void operator()() {n = 20;}
};
class unnamed3
{
int n;
public:
unnamed3(int N) : n(N) {}
/* BAD. Your this is const so you can't modify the "n" member. */
void operator()() const {n = 10;}
};
int main()
{
int n;
unnamed1 u1(n); u1(); // OK
unnamed2 u2(n); u2(); // OK
//unnamed3 u3(n); u3(); // Error
std::cout << n << "\n"; // "10"
}
So you could think of lambdas as generating a class with operator() that defaults to const unless you say that it is mutable.
You can also think of all the variables captured inside [] (explicitly or implicitly) as members of that class: copies of the objects for [=] or references to the objects for [&]. They are initialized when you declare your lambda as if there was a hidden constructor.
I was under the impression that the whole point of capture-by-value is to allow the user to change the temporary -- otherwise I'm almost always better off using capture-by-reference, aren't I?
The question is, is it "almost"? A frequent use-case appears to be to return or pass lambdas:
void registerCallback(std::function<void()> f) { /* ... */ }
void doSomething() {
std::string name = receiveName();
registerCallback([name]{ /* do something with name */ });
}
I think that mutable isn't a case of "almost". I consider "capture-by-value" like "allow me to use its value after the captured entity dies" rather than "allow me to change a copy of it". But perhaps this can be argued.
You have to understand what capture means! it's capturing not argument passing! let's look at some code samples:
int main()
{
using namespace std;
int x = 5;
int y;
auto lamb = [x]() {return x + 5; };
y= lamb();
cout << y<<","<< x << endl; //outputs 10,5
x = 20;
y = lamb();
cout << y << "," << x << endl; //output 10,20
}
As you can see even though x has been changed to 20 the lambda is still returning 10 ( x is still 5 inside the lambda)
Changing x inside the lambda means changing the lambda itself at each call (the lambda is mutating at each call). To enforce correctness the standard introduced the mutable keyword. By specifying a lambda as mutable you are saying that each call to the lambda could cause a change in the lambda itself. Let see another example:
int main()
{
using namespace std;
int x = 5;
int y;
auto lamb = [x]() mutable {return x++ + 5; };
y= lamb();
cout << y<<","<< x << endl; //outputs 10,5
x = 20;
y = lamb();
cout << y << "," << x << endl; //outputs 11,20
}
The above example shows that by making the lambda mutable, changing x inside the lambda "mutates" the lambda at each call with a new value of x that has no thing to do with the actual value of x in the main function
FWIW, Herb Sutter, a well-known member of the C++ standardization committee, provides a different answer to that question in Lambda Correctness and Usability Issues:
Consider this straw man example, where the programmer captures a local variable by
value and tries to modify the
captured value (which is a member variable of the lambda object):
int val = 0;
auto x = [=](item e) // look ma, [=] means explicit copy
{ use(e,++val); }; // error: count is const, need ‘mutable’
auto y = [val](item e) // darnit, I really can’t get more explicit
{ use(e,++val); }; // same error: count is const, need ‘mutable’
This feature appears to have been added out of a concern that the user
might not realize he got a copy, and in particular that since lambdas
are copyable he might be changing a different lambda’s copy.
His paper is about why this should be changed in C++14. It is short, well written, worth reading if you want to know "what's on [committee member] minds" with regards to this particular feature.
You need to think what is the closure type of your Lambda function. Every time you declare a Lambda expression, the compiler creates a closure type, which is nothing less than an unnamed class declaration with attributes (environment where the Lambda expression where declared) and the function call ::operator() implemented. When you capture a variable using copy-by-value, the compiler will create a new const attribute in the closure type, so you can't change it inside the Lambda expression because it is a "read-only" attribute, that's the reason they call it a "closure", because in some way, you are closing your Lambda expression by copying the variables from upper scope into the Lambda scope. When you use the keyword mutable, the captured entity will became a non-const attribute of your closure type. This is what causes the changes done in the mutable variable captured by value, to not be propagated to upper scope, but keep inside the stateful Lambda.
Always try to imagine the resulting closure type of your Lambda expression, that helped me a lot, and I hope it can help you too.
See this draft, under 5.1.2 [expr.prim.lambda], subclause 5:
The closure type for a lambda-expression has a public inline function call operator (13.5.4) whose parameters
and return type are described by the lambda-expression’s parameter-declaration-clause and trailingreturn-
type respectively. This function call operator is declared const (9.3.1) if and only if the lambdaexpression’s
parameter-declaration-clause is not followed by mutable.
Edit on litb's comment:
Maybe they thought of capture-by-value so that outside changes to the variables aren't reflected inside the lambda? References work both ways, so that's my explanation. Don't know if it's any good though.
Edit on kizzx2's comment:
The most times when a lambda is to be used is as a functor for algorithms. The default constness lets it be used in a constant environment, just like normal const-qualified functions can be used there, but non-const-qualified ones can't. Maybe they just thought to make it more intuitive for those cases, who know what goes on in their mind. :)
I was under the impression that the
whole point of capture-by-value is to
allow the user to change the temporary
-- otherwise I'm almost always better off using capture-by-reference, aren't
I?
n is not a temporary. n is a member of the lambda-function-object that you create with the lambda expression. The default expectation is that calling your lambda does not modify its state, therefore it is const to prevent you from accidentally modifying n.
To extend Puppy's answer, lambda functions are intended to be pure functions. That means every call given a unique input set always returns the same output. Let's define input as the set of all arguments plus all captured variables when the lambda is called.
In pure functions output solely depends on input and not on some internal state. Therefore any lambda function, if pure, does not need to change its state and is therefore immutable.
When a lambda captures by reference, writing on captured variables is a strain on the concept of pure function, because all a pure function should do is return an output, though the lambda does not certainly mutate because the writing happens to external variables. Even in this case a correct usage implies that if the lambda is called with the same input again, the output will be the same everytime, despite these side effects on by-ref variables. Such side effects are just ways to return some additional input (e.g. update a counter) and could be reformulated into a pure function, for example returning a tuple instead of a single value.
I also was wondering about it and the simplest explanation why [=] requires explicit mutable is in this example:
int main()
{
int x {1};
auto lbd = [=]() mutable { return x += 5; };
printf("call1:%d\n", lbd());
printf("call2:%d\n", lbd());
return 0;
}
Output:
call1:6
call2:11
By words:
You can see that the x value is different at the second call (1 for the call1 and 6 for the call2).
A lambda object keeps a captured variable by value (has its own
copy) in case of [=].
The lambda can be called several times.
And in general case we have to have the same value of the captured variable to have the same predictable behavior of the lambda based on the known captured value, not updated during the lambda work. That's why the default behavior assumed const (to predict changes of the lambda object members) and when a user is aware of consequences he takes this responsibility on himself with mutable.
Same with capturing by value. For my example:
auto lbd = [x]() mutable { return x += 5; };
There is now a proposal to alleviate the need for mutable in lambda declarations: n3424
You might see the difference, if you check 3 different use cases of lambda:
Capturing an argument by value
Capturing an argument by value with 'mutable' keyword
Capturing an argument by reference
case 1:
When you capture an argument by value, a few things happen:
You are not allowed to modify the argument inside the lambda
The value of the argument remains the same, whenever the lambda is
called, not matter what will be the argument value at the time the lambda is called.
so for example:
{
int x = 100;
auto lambda1 = [x](){
// x += 2; // compile time error. not allowed
// to modify an argument that is captured by value
return x * 2;
};
cout << lambda1() << endl; // 100 * 2 = 200
cout << "x: " << x << endl; // 100
x = 300;
cout << lambda1() << endl; // in the lambda, x remain 100. 100 * 2 = 200
cout << "x: " << x << endl; // 300
}
Output:
200
x: 100
200
x: 300
case 2:
Here, when you capture an argument by value and use the 'mutable' keyword, similar to the first case, you create a "copy" of this argument. This "copy" lives in the "world" of the lambda, but now, you can actually modify the argument within the lambda-world, so its value is changed, and saved and it can be referred to, in the future calls of this lambda. Again, the outside "life" of the argument might be totally different (value wise):
{
int x = 100;
auto lambda2 = [x]() mutable {
x += 2; // when capture by value, modify the argument is
// allowed when mutable is used.
return x;
};
cout << lambda2() << endl; // 100 + 2 = 102
cout << "x: " << x << endl; // in the outside world - x remains 100
x = 200;
cout << lambda2() << endl; // 104, as the 102 is saved in the lambda world.
cout << "x: " << x << endl; // 200
}
Output:
102
x: 100
104
x: 200
case 3:
This is the easiest case, as no more 2 lives of x. Now there is only one value for x and it's shared between the outside world and the lambda world.
{
int x = 100;
auto lambda3 = [&x]() mutable {
x += 10; // modify the argument, is allowed when mutable is used.
return x;
};
cout << lambda3() << endl; // 110
cout << "x: " << x << endl; // 110
x = 400;
cout << lambda3() << endl; // 410.
cout << "x: " << x << endl; // 410
}
Output:
110
x: 110
410
x: 410