1

I've recently learned that I can do this:

auto a = +[]{return true;};
a = +[]{return false;};

And understood that the capture-free lambda decays to a function pointer, as confirmed by GCC:

bool (*)()

But where is the actual function object stored? How is it freed? Why can I store a pointer to a temporary lambda? I understand that corner-case of the the language where constant references extend the lifetime of an object, so I expected the lambda to decay to something of that kind, not a raw pointer.

Community
  • 1
  • 1
Kahler
  • 1,130
  • 6
  • 24
  • If you're interested, you can refer to [Clang's source code](https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaLambda.cpp#L1147). – chris Jul 28 '16 at 02:23
  • 4
    When you write `bool foo() {return true;}` and then write `auto a = &foo;` how is `foo` freed? Answer: it isn't. – user253751 Jul 28 '16 at 02:56
  • @immibis that's enlightening – Kahler Jul 28 '16 at 02:58
  • @chris hard reading for me. I ~think~ I understood the conversion and the requirements for it, but haven't found why the lambda just doesn't collapses and die (drama) as other temporaries after the sequence point. Maybe it's a compiler trick associated with the uniqueness of each lambda type. – Kahler Jul 28 '16 at 04:52

1 Answers1

5

The lambda is not a pointer, but can be converted into a pointer-to-function.

Functions are not "stored" like values in C++. In practice, they exist in a code segment of the executable, and are loaded into write-protected execute-bit-set pages by the executable/dll loader.

The stateless lambda's code is no different. The conversion just returns a pointer to a function with the same effect as the body of the lambda, no more, no less.

Remember this only works with stateless lambdas. There is no non-static data to be stored.

Now, the + thing is a bit of a trick, in that when you apply unary operator+ to an object, conversion is attempted, and one uniqie type (conversion of the function object to function pointer) is found.

I guess concrete code may help.

struct fake_lambda {
  static void action(){ std::cout<<"hello?\n"; }
  void operator()()const{action();}
  using ptr=void(*)();
  operator ptr()const{return &fake_lambda::action;}
};

Now auto f=+fake_lambda{}; is a pointer to a function that prints "hello?\n".

This is basically the same as auto f=+[](){std::cout<<"hello\n";};, but more verbose.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • The static/not stored part confuses me a bit... If the code is keep in a separate region, does it mean I can safely [return a decayed pointer to a local lambda](http://coliru.stacked-crooked.com/a/fc9d87a68f5c4795)? – Kahler Jul 28 '16 at 03:29
  • ...or is the protected segment you mentioned local and unwinded just like local variables when the function return? – Kahler Jul 28 '16 at 04:47
  • 2
    @kahler C++ has no concept or possibility for a function pointer to an actual function to no longer be valid. (It can be uninitialized, or null, or assigned to by either, but a valid function pointer and its copies cannot become invalid). Now in reality with dynamic linking and dll unloading it can happen, but the C++ standard does not describe dynamic linking loading or unloading. In short, is the lambda in a dll, and has the dll been unloaded? Probably not, or you'd be asking a different question. So the pointer is valid for lifetime of program. – Yakk - Adam Nevraumont Jul 28 '16 at 07:54