我对lambda表达式的变量捕获部分的性质感到困惑。
void f1();
std::function<int()> f2;
int main() {
f1();
std::cout<<f2()<<endl;
}
void f1() {
int x;
f2 = [&]() {
return x;
};
}
在x
被调用之前,f2
是否被解构了?
答案 0 :(得分: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,没有理由不按值存储它:对于更复杂的类型,您可能希望避免不必要地复制它。)
请注意,上面的评论以更有趣的方式解释了这一点。
现在,一些编译器会将堆栈标记为特殊值,当你递减它以捕获这种未定义的行为时(并且通过catch,我的意思是让程序员更明显)。但是在大多数情况下,可以在C ++中调用未定义的行为。
答案 1 :(得分:2)
在调用f2之前是不是解构了x?
是的,确实如此。这意味着return x
会评估悬空引用,该引用会调用未定义的行为。
在这种情况下,您可能更愿意按值捕获。
f2 = [x]() { return x; }