Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

const static auto lambda used with capture by reference

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.

  • Is foo bound at the first invocation and then kept bound to a stack address which becomes invalid on successive invocations?
  • Am I forced so drop 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?

like image 332
Jack Avatar asked Jun 23 '15 10:06

Jack


People also ask

Are lambda captures const?

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.

What does lambda capture mean?

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.

How do you capture a variable in lambda function?

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] () { //... };

How do you declare lambda in C++?

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.


1 Answers

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).

like image 92
Angew is no longer proud of SO Avatar answered Oct 06 '22 11:10

Angew is no longer proud of SO