什么是C ++ lambdaexpression式的生命周期?
(我已经读过C ++中lambda派生的隐式函子的生命周期了 ,它并没有回答这个问题。)
我明白,C ++ lambda语法只是用一个调用操作符和某个状态来创build一个匿名类的实例,而我理解该状态的生命周期需求(由是否通过引用的值捕获来决定)。 lambda对象本身的生命周期? 在下面的例子中,返回的std::function
实例是否有用?
std::function<int(int)> meta_add(int x) { auto add = [x](int y) { return x + y; }; return add; }
如果是,它是如何工作的 ? 这似乎有点太神奇了 – 我只能想象它通过std::function
复制我的整个实例,这可能是非常沉重取决于我所捕获的 – 在过去,我已经使用std::function
主要与裸函数指针,并复制这些很快。 从std::function
的types擦除来看,它也有问题。
如果你用一个手工轧制的仿函数replace你的lambda,生命就是这样:
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; }
该对象将被创build,在meta_add
函数中是本地的,然后[包括x
的值在内]移动到返回值中,然后本地实例将超出范围并被正常销毁。 但是从函数返回的对象只要保存它的std::function
对象就会保持有效。 这显然取决于调用上下文多长时间。
看来你对std::function
比lambdas更困惑。
std::function
使用了一种称为type-erasure的技术。 这是一个快速的飞行。
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; };
你为什么要删除这个types? 是不是我们想要的types只是int (*)(float)
?
擦除types允许Erased
现在可以存储任何可调用的值,如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; } );
这是:
[x](int y) { return x + y; };
相当于:(或者也可以考虑)
struct MyLambda { MyLambda(int x): x(x) {} int operator()(int y) const { return x + y; } private: int x; };
所以你的对象正在返回一个看起来就像这样的对象。 其中有一个定义良好的复制构造函数。 所以看起来非常合理,它可以正确地从一个函数中拷贝出来。
在你发布的代码中:
std::function<int(int)> meta_add(int x) { auto add = [x](int y) { return x + y; }; return add; }
std::function<int(int)>
返回的std::function<int(int)>
对象实际上包含已分配给局部variablesadd
的lambda函数对象的移动实例。
当定义一个按值或按引用捕获的C ++ 11 lambda时,C ++编译器自动生成一个唯一的函数types,当lambda被调用或分配给一个variables时,它的一个实例被创build。 为了说明,你的C ++编译器可能为[x](int y) { return x + y; }
定义的lambda生成以下类types[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; } };
然后, meta_add
函数基本上等同于:
std::function<int(int)> meta_add(int x) { __lambda_373s27a add = __lambda_373s27a(x); return add; }
编辑:顺便说一句,我不知道如果你知道这一点,但这是一个函数在C ++ 11中的例子。