[英]What is the lifetime of a C++ lambda expression?
(我已經閱讀了C ++中lambda派生的隱式仿函數的生命周期是什么?已經沒有回答這個問題了。)
我理解C ++ lambda語法只是用於創建具有調用操作符和某個狀態的匿名類的實例的糖,並且我理解該狀態的生存期要求(由您是否通過引用的值捕獲來決定。)但是什么是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
的類型擦除,它似乎也有問題。
如果用手動編織器代替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;
}
該對象將在meta_add
函數的本地創建,然后[在其entirty中,包括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;
};
你為什么要刪除這個類型? 我們想要的類型不是int (*)(float)
嗎?
類型擦除允許的是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)>
對象實際上包含已分配給局部變量add
的lambda函數對象的移動實例。
當您定義捕獲按值或按引用的C ++ 11 lambda時,C ++編譯器會自動生成一個唯一的函數類型,其實例是在調用lambda或賦值給變量時構造的。 為了說明,您的C ++編譯器可能會為[x](int y) { return x + y; }
定義的lambda生成以下類類型[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中函數currying的一個例子。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.