While using some local lambda objects in a C++11 function I was tempted to declare them as const static auto lambda = ...
just to let the compiler know that there is just one std::function
object needed (and possibly optimize the call and/or inline it) but I realized that capturing local values by reference in this circumstance leads to weird behavior.
Consider the following code:
void process(const Data& data, const std::function<void(DataElement&>& lambda) {
...
}
void SomeClass::doSomething()
{
int foo = 0;
const static auto lambda = [&foo] () { .... ++foo; .... }
process(data, lambda);
}
This doesn't work with multiple invocations of doSomething()
but the mechanics is not clear.
foo
bound at the first invocation and then kept bound to a stack address which becomes invalid on successive invocations?static
in this circumstance?Where is this behavior specified in the standard? Considering it's a static
variable where is it constructed? Lazily on first invocation of doSomething()
(so that the first invocation works) or at program start?
By default, variables are captured by const value . This means when the lambda is created, the lambda captures a constant copy of the outer scope variable, which means that the lambda is not allowed to modify them.
The lambda is capturing an outside variable. A lambda is a syntax for creating a class. Capturing a variable means that variable is passed to the constructor for that class. A lambda can specify whether it's passed by reference or by value.
Capturing Local Variables by value inside Lambda Function To capture the local variables by value, specify their name in capture list i.e. }; // Local Variables std::string msg = "Hello"; int counter = 10; // Defining Lambda function and // Capturing Local variables by Value auto func = [msg, counter] () { //... };
Creating a Lambda Expression in C++auto greet = []() { // lambda function body }; Here, [] is called the lambda introducer which denotes the start of the lambda expression. () is called the parameter list which is similar to the () operator of a normal function.
A static function-scope variable is initialised "lazily," when control flow first reaches its declaration. This means that the capture by reference does indeed bind to the foo
currently on stack, and when the call terminates, that binding becomes dangling.
Don't try to help the compiler too much; making lambda
static
looks like a micro-optimisation, with very bad side effects. There's next to no overhead involved in actually creating a closure object, and the compiler can easily inline it regardless of whether it's static
or not.
Not to mention the fact that you're not saving on creating the std::function
object even with your approach. The type of a lambda expression is an unnamed closure object, not std::function
. So even if lambda
is static
, the std::function
object is created in each call anyway (unless the whole thing is inlined).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With