Lambda:一个可以悬挂的按引用捕获
Lambda: A by-reference capture that could dangle
Scott Meyers在《Effective Modern c++》的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
的引用现在是悬空的。
据我所知,过滤器。Emplace_back仅在lambda表达式完成后返回,并且在执行期间,除数是有效的。
那不是真的。vector存储从闭包创建的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
的引用是无效的。
相关文章:
- 引用一个已擦除类型(void*)的指针
- 在 C++ 03 中,如何引用一个被煽动的模板函数的地址
- 如何在C (转换Python代码)中引用一个函数
- C++11是否允许引用一个匿名的临时文件
- 你能取消引用一个整数文本吗
- 指针和引用:一个简单的例子
- 取消引用一个空指针数组
- 在C++中,如果我引用一个具有解除分配析构函数~MyClass的对象,那么超出范围的引用会调用析构函数吗
- 如何初始化boost::any并引用一个对象
- 我如何使一个函数指针引用一个局部变量
- 为什么我不需要解引用一个char指针来输出c风格的字符串?
- 如何引用一个静态函数作为参数传递
- 解引用一个超出边界50%的指针(数组的数组)
- 如何将Java中的开关替换为每个情况引用一个变量的列表?
- 试图引用一个被删除的函数
- 试图引用一个被删除的函数,VS 2015
- 我将如何引用一个自定义库与另一个库在c++
- 引用一个未命名的临时对象(生命周期)
- 为什么函数总是引用一个特定的参数
- "unresolved external symbol"从另一个类引用一个类