3

以下代码工作正常:

#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++;
    };
}

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

4

2 回答 2

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,您都会得到一个单独的对象,其中包含它自己的增量计数。

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

于 2013-05-25T15:19:22.077 回答
2

你明确地告诉编译器你想通过引用来获取变量,所以它假设你有你的理由并按照你告诉它做的事情去做。

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

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

于 2013-05-25T15:19:56.590 回答