我對lambda表達式的變量捕獲部分的性質感到困惑。Lambda變量捕獲
void f1();
std::function<int()> f2;
int main() {
f1();
std::cout<<f2()<<endl;
}
void f1() {
int x;
f2 = [&]() {
return x;
};
}
是不是x
f2
之前解構叫?
我對lambda表達式的變量捕獲部分的性質感到困惑。Lambda變量捕獲
void f1();
std::function<int()> f2;
int main() {
f1();
std::cout<<f2()<<endl;
}
void f1() {
int x;
f2 = [&]() {
return x;
};
}
是不是x
f2
之前解構叫?
在f2被調用之前x沒有被解構嗎?
是的。這意味着return x
將評估一個懸空引用,該引用會調用未定義的行爲。
在這種情況下,您可能更願意按值進行捕獲。
f2 = [x]() { return x; }
它只是'[x]'。 '[=]'用於按值自動捕獲未命名的外部項目。 – moswald
是的。您已成功調用未定義的行爲。一個可能的結果是你得到了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++中調用未定義的行爲是可能的。
我認爲這是UB! –
請閱讀[本答案](http://stackoverflow.com/a/6445794/734069)。 –
如果將lambda傳遞給線程(想到「異步」),事情會變得更糟。 – Ali