C ++ lambda中的静态变量

时间:2013-05-25 15:14:47

标签: c++ c++11 lambda

以下代码可以正常使用:

#include <iostream>
#include <functional>

std::function<int (void)> get_incrementer() {
    return []() {
        static int count = 0;
        return count++;
    };
}

int main() {
    using std::cout;

    auto incrementer = get_incrementer();

    cout << incrementer() << std::endl;
    cout << incrementer() << std::endl;

    return 0;
}

但是如果你通过引用捕获局部变量,它会突然导致未定义的行为,因为在调用时,堆栈上的位置正被其他东西使用。

std::function<int (void)> get_incrementer() {
    int count = 0;

    return [&count]() {
        return count++;
    };
}

为什么编译器允许它呢?我希望编译器要么不允许这样做(检查这种情况似乎微不足道)或者改变局部变量的存储持续时间。

2 个答案:

答案 0 :(得分:7)

C ++允许它,因为C ++不是安全语言。虽然这种情况可能是“微不足道”来检查(并且个人而言,我不同意它是微不足道的,但我不是编译器编写者),还有很多其他情况琐碎的检查。

C ++不是修复您破坏的代码的业务。它确实只是你告诉它的,即使它是非常不明智的。

此外,还不完全清楚你打算用这个代码做什么。例如,这些是两个完全不同的东西:

std::function<int (void)> get_incrementer() {
    return []() {
        static int count = 0;
        return count++;
    };
}

std::function<int (void)> get_incrementer() {
    int count = 0;
    return [count]() mutable {
        return count++;
    };
}

在第一种情况下,返回函数的每个实例将共享相同的增量计数。在第二种情况下,每次调用get_incrementer时,您将获得一个单独的对象,其中包含自己的增量计数。

用户想要哪一个?目前尚不清楚。所以你不能随便“纠正”它。

答案 1 :(得分:2)

您明确告诉编译器您希望通过引用获取变量,因此它假定您有自己的理由并按照您的要求执行操作。

您是主人,编译器只是满足您的需求并遵守您的意愿。 它可能会在某些情况下警告你,当它认为你正在做一些特别奇怪的事情,但如果你坚持,它会尊重你的权威并编译那些看起来奇怪的代码。

在局部变量超出范围之后使用对局部变量的引用总是未定义的行为并且不会有任何好处,使用lambda来完成它并不是那么特别。