Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where are lambda captured variables stored?

Tags:

c++

memory

lambda

How is it possible that this example works? It prints 6:

#include <iostream> #include <functional>  using namespace std;  void scopeIt(std::function<int()> &fun) {     int val = 6;     fun = [=](){return val;}; //<-- this }  int main() {     std::function<int()> fun;      scopeIt(fun);      cout << fun();      return 0; } 

Where is the value 6 stored after scopeIt is done being called? If I replace the [=] with a [&], it prints 0 instead of 6.

like image 761
BWG Avatar asked Jan 14 '15 23:01

BWG


2 Answers

It is stored within the closure, which - in your code - is then stored within std::function<int()> &fun.

A lambda generates what's equivalent to an instance of a compiler generated class.

This code:

[=](){return val;} 

Generates what's effectively equivalent to this... this would be the "closure":

struct UNNAMED_TYPE {   UNNAMED_TYPE(int val) : val(val) {}   const int val;   // Above, your [=] "equals/copy" syntax means "find what variables   //           are needed by the lambda and copy them into this object"    int operator() () const { return val; }   // Above, here is the code you provided  } (val); // ^^^ note that this DECLARED type is being INSTANTIATED (constructed) too!! 
like image 137
Drew Dormann Avatar answered Oct 06 '22 02:10

Drew Dormann


Lambdas in C++ are really just "anonymous" struct functors. So when you write this:

int val = 6; fun = [=](){return val;}; 

What the compiler is translating that into is this:

int val = 6; struct __anonymous_struct_line_8 {     int val;     __anonymous_struct_line_8(int v) : val(v) {}      int operator() () const {         return val; // returns this->val     } };  fun = __anonymous_struct_line_8(val); 

Then, std::function stores that functor via type erasure.

When you use [&] instead of [=], it changes the struct to:

struct __anonymous_struct_line_8 {     int& val; // Notice this is a reference now!     ... 

So now the object stores a reference to the function's val object, which becomes a dangling (invalid) reference after the function exits (and you get undefined behavior).

like image 27
Cornstalks Avatar answered Oct 06 '22 00:10

Cornstalks