Lambda变量捕获

时间:2012-10-26 19:45:10

标签: c++ lambda c++11

我对lambda表达式的变量捕获部分的性质感到困惑。

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

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

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

x被调用之前,f2是否被解构了?

2 个答案:

答案 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; }