繁体   English   中英

Lambda:可以悬挂的副引用捕获

[英]Lambda: A by-reference capture that could dangle

有效的现代C ++中的Scott Meyers在lambda章节中说:

请考虑以下代码:

void addDivisorFilter()
{
    auto calc1 = computeSomeValue1();
    auto calc2 = computeSomeValue2();

    auto divisor = computeDivisor(calc1, calc2);

    filters.emplace_back(
          [&](int value) { return value % divisor == 0; }
    );
}

这段代码是一个等待发生的问题。 lambda引用局部变量divisor ,但当addDivisorFilter返回时,该变量不再存在。 这是在filters.emplace_back返回后立即执行的,因此添加到filters的函数在到达时基本上是死的。 使用该过滤器几乎从创建时开始产生未定义的行为。

问题是:为什么它是一个未定义的行为? 根据我的理解, filters.emplace_back仅在lambda表达式完成后返回,并且在执行期间, divisor有效。

更新

我错过的重要数据包括:

using FilterContainer = std::vector<std::function<bool(int)>>;
FilterContainer filters;

那是因为向量filters的范围超过了其中一个函数。 在函数出口处,向量filters仍然存在,并且捕获的对divisor引用现在是悬空的。

根据我的理解,filters.emplace_back仅在lambda表达式完成后返回,并且在执行期间,除数有效。

这不是真的。 向量存储从闭包创建的lambda,并且不“执行”lambda,在函数退出后执行lambda。 从技术上讲,lambda是从一个内部使用引用的闭包(一个依赖于编译器的类)构造的

#include <vector>
#include <functional>

struct _AnonymousClosure
{
    int& _divisor; // this is what the lambda captures
    bool operator()(int value) { return value % _divisor == 0; }
};

int main()
{
    std::vector<std::function<bool(int)>> filters;
    // local scope
    {
        int divisor = 42;
        filters.emplace_back(_AnonymousClosure{divisor});
    }
    // UB here when using filters, as the reference to divisor dangle
}

在addDivisorFilter处于活动状态时,您没有评估lambda函数。 您只是将“函数”添加到集合中,而不知道何时可以对其进行评估(可能在addDivisorFilter返回后很长时间)。

除了@ vsoftco的答案之外,以下修改过的示例代码可以让您体验到这个问题:

#include <iostream>
#include <functional>
#include <vector>

void addDivisorFilter(std::vector<std::function<int(int)>>& filters)
{
    int divisor = 5;

    filters.emplace_back(
          [&](int value) { return value % divisor == 0; }
    );
}

int main()
{
    std::vector<std::function<int(int)>> filters;
    addDivisorFilter(filters);
    std::cout << std::boolalpha << filters[0](10) << std::endl;
    return 0;
}

实例

此示例在运行时导致Floating point exception ,因为当在main计算lambda时,对divisor的引用无效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM