Scott Meyers,在Effective Modern C ++中,在lambda章节中说:
请考虑以下代码:
divisor
此代码是一个等待发生的问题。 lambda引用局部变量
addDivisorFilter
,但当filters.emplace_back
返回时,该变量不再存在。在filters
返回后立即执行此操作,因此添加到filters.emplace_back
的功能在到达时基本上已死亡。使用该过滤器几乎从它创建的那一刻开始产生未定义的行为。
问题是:为什么它是一个未定义的行为?根据我的理解,divisor
仅在lambda表达式完成后返回,并且在执行期间using FilterContainer = std::vector<std::function<bool(int)>>;
FilterContainer filters;
有效。
更新
我错过的重要数据包括:
<% Artist.tag_counts_on(:tag).each do |some_value| %>
<%= f.check_box(:tag_list, { :multiple => true }, some_value, nil) %>
<% end %>
答案 0 :(得分:6)
这是因为向量filters
的范围超过了函数之一。在函数退出处,向量filters
仍然存在,并且捕获的对divisor
的引用现在正在悬空。
根据我的理解,filters.emplace_back仅在lambda表达式完成后返回,并且在执行期间,divisor有效。
那不是真的。向量存储从闭包创建的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
}
答案 1 :(得分:1)
当addDivisorFilter处于活动状态时,您没有评估lambda函数。您只需添加&#34;功能&#34;收集,不知道什么时候可以评估(可能在addDivisorFilter返回后很久)。
答案 2 :(得分:1)
除了@ 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
,因为在divisor
中评估lambda时,对main
的引用无效。