![](/img/trans.png)
[英]C++11 lambda: when do we need to capture [*this] instead of [this]?
[英]C++11 lambda - why do I need to capture auto duration variables?
在捕獲'[]'部分中編寫lambda函數時,我需要僅指定自動持續時間變量,而在lambda函數中使用全局變量和靜態變量而不需要捕獲。 這是為什么? 為什么我們不能像全局變量和靜態變量一樣使用自動持續時間變量?
因為lambda定義了一個單獨的范圍:它等效於:
int global_i;
struct Lambda {
Lambda(int captured_j) : captured_j(captured_j) {}
void operator()(){
// in this scope, global_i is accessible, and by capturing auto_j, we make that visible as well, but we can't see auto_i
}
int captured_j;
}
void foo() {
int auto_i;
int auto_j
// this lambda
[j](){}
// is just shorthand for this:
Lambda lambda(j);
}
lambda由編譯器轉換為函數對象(就像我的示例中的Lambda
類)。 並且函數對象無法訪問在實例化函數對象的范圍內聲明的局部變量。 除非你通過將它們傳遞給構造函數來“捕獲”它們。
至於為什么編譯器沒有隱式地執行此操作,而不要求您提示它,它不能,因為它不知道您是想要按值還是通過引用捕獲。 在GC語言中,您始終通過引用捕獲,因為它無關緊要 - 只要您需要它們,您引用的對象就會保持活動狀態。
但是在C ++中,您需要管理這些對象的生命周期,如果lambda總是通過引用捕獲,那么它在聲明范圍之外幾乎是無用的(因為它將包含對已被銷毀的對象的引用)。 因此,在C ++中,您必須指定是否要按值或引用進行捕獲。 因為你必須指定它,編譯器不能只為你做。
考慮這個簡單的功能:
std::function<foo()> f()
{
foo afoo;
return [=](){ return afoo; };
}
int main()
{
auto l = f();
l();
}
如果你沒有捕獲變量afoo
,它會在lamda形成的閉包被使用之前超出范圍!
另請注意,我使用by-value capture完全出於同樣的原因:返回引用/指向局部變量的指針具有未定義的行為。
從本質上講,lambda並沒有太大的魔力; 簡單地認為它是一個匿名的仿函數。
傳統的仿函數也不知道它所包含的局部變量,你需要將它們提供給它的ctor。 像lambda這樣的匿名事物沒有可自定義的c'tor,因此您可以通過這種“[]”語法提供上下文。
或考慮一下
const float g_foo = 42.f;
struct A {
float _bar;
struct B {
B() : _baz(_bar /*oops*/) {}
float _baz;
};
};
在A :: B的閉包中,沒有A的“_bar”概念,但g_foo會被人知道。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.