What is the lifetime of a C ++ lambda expression?

(I read What is the lifetime of lambda-derived implicit functors in C ++? And already does not answer this question.)

I understand that the C ++ lambda syntax is just sugar to create an instance of an anonymous class with a call operator and some state, and I understand the life requirements of this state (whether your capture is determined by value by reference). But what is the lifetime of the lambda object itself? The following example returns an instance of std::function , which will be useful?

 std::function<int(int)> meta_add(int x) { auto add = [x](int y) { return x + y; }; return add; } 

If so, how does it work? It seems to me that this is too much magic - I can only imagine that it works with copying my entire instance, which can be very difficult depending on what I captured - in the past I used std::function mostly with bare function pointers and copy them quickly. This also seems problematic in light of erasing the type std::function .

+57
c ++ lambda c ++ 11
Oct 29 '11 at 20:44
source share
4 answers

Lifetime is exactly what it would be if you replaced your lambda with a manual functor:

 struct lambda { lambda(int x) : x(x) { } int operator ()(int y) { return x + y; } private: int x; }; std::function<int(int)> meta_add(int x) { lambda add(x); return add; } 

The object will be created locally for the meta_add function, and then transferred [to its entirty, including the value of x ] to the return value, then the local instance will go beyond the scope and will be destroyed as normal. But the object returned by the function will remain valid as long as the object std::function that supports it. How long this obviously depends on the calling context.

+51
Oct 29 '11 at 20:54
source share

You seem to be more confused about std::function than lambdas.

std::function uses a method called type erasure. Fly fast here.

 class Base { virtual ~Base() {} virtual int call( float ) =0; }; template< typename T> class Eraser : public Base { public: Eraser( T t ) : m_t(t) { } virtual int call( float f ) override { return m_t(f); } private: T m_t; }; class Erased { public: template<typename T> Erased( T t ) : m_erased( new Eraser<T>(t) ) { } int do_call( float f ) { return m_erased->call( f ); } private: Base* m_erased; }; 

Why do you want to delete a type? Not the type we want just int (*)(float) ?

That allows type erasure, Erased can now store any value that can be called as int(float) .

 int boring( float f); short interesting( double d ); struct Powerful { int operator() ( float ); }; Erased e_boring( &boring ); Erased e_interesting( &interesting ); Erased e_powerful( Powerful() ); Erased e_useful( []( float f ) { return 42; } ); 
+13
Oct 31 '11 at 16:40
source share

It:

 [x](int y) { return x + y; }; 

Equivalent: (or may be considered too)

 struct MyLambda { MyLambda(int x): x(x) {} int operator()(int y) const { return x + y; } private: int x; }; 

Thus, your object returns an object that looks exactly like that. Which has a well-defined copy constructor. Therefore, it seems reasonable that it can be correctly copied from a function.

+9
Oct 29 '11 at 20:52
source share

In the code you posted:

 std::function<int(int)> meta_add(int x) { auto add = [x](int y) { return x + y; }; return add; } 

The std::function<int(int)> object returned by the function actually contains the moved instance of the lambda function object that was assigned to the local variable add .

When you define a lambda C ++ 11 that captures by value or by reference, the C ++ compiler automatically generates a unique function type, an instance of which is created when the lambda is called or assigned to a variable. To illustrate, your C ++ compiler can generate the following class type for the lambda defined by [x](int y) { return x + y; } [x](int y) { return x + y; } :

 class __lambda_373s27a { int x; public: __lambda_373s27a(int x_) : x(x_) { } int operator()(int y) const { return x + y; } }; 

Then the meta_add function is essentially equivalent:

 std::function<int(int)> meta_add(int x) { __lambda_373s27a add = __lambda_373s27a(x); return add; } 

EDIT:. By the way, I'm not sure if you know this, but this is an example of the currying function in C ++ 11.

+4
Oct 29 2018-11-21T00:
source share



All Articles