2012-10-26 96 views
0

我對lambda表達式的變量捕獲部分的性質感到困惑。Lambda變量捕獲

void f1(); 
std::function<int()> f2; 

int main() { 
    f1(); 
    std::cout<<f2()<<endl; 
} 

void f1() { 
    int x; 
    f2 = [&]() { 
     return x; 
    }; 
} 

是不是xf2之前解構叫?

+0

我認爲這是UB! –

+4

請閱讀[本答案](http://stackoverflow.com/a/6445794/734069)。 –

+0

如果將lambda傳遞給線程(想到「異步」),事情會變得更糟。 – Ali

回答

2

在f2被調用之前x沒有被解構嗎?

是的。這意味着return x將評估一個懸空引用,該引用會調用未定義的行爲。

在這種情況下,您可能更願意按值進行捕獲。

f2 = [x]() { return x; } 
+0

它只是'[x]'。 '[=]'用於按值自動捕獲未命名的外部項目。 – moswald

4

是的。您已成功調用未定義的行爲。一個可能的結果是你得到了x的值。另一個原因是計算機格式化你的硬盤,程序崩潰,或者電腦變成一個機器人貝克刺客,給你紙杯蛋糕,錯誤地認爲你有乳糜瀉。

這方面的一個安全的變體可能是:

int main() { 
    f1(7); 
    std::cout<<f2()<<endl; 
} 

void f1(int x) { 
    std::shared_ptr<int> spX(new int(x)); 
    f2 = [=]() { 
     return *spX; 
    }; 
} 

void f1(int x) { 
    f2 = [=]() { 
     return x; 
    }; 
} 

(類型爲int的,有什麼理由不按價值計算其存儲:一個更復雜的類型,你可能希望避免不必要地複製它)。

請注意,上面的評論以更有趣的方式解釋了這一點。

現在,一些編譯器會在您將其遞減以準確捕獲這種未定義的行爲時(以及捕獲,我的意思是讓程序員更明顯)用特殊值標記堆棧。但大多數情況下,在C++中調用未定義的行爲是可能的。