在
this article它说下面的代码是有效的C 11,并与GNU的libstdc:
int n; std::vector<int> v; ... std::function<bool(int)> f(std::cref([n](int i) {return i%n == 0)); std::count_if(v.begin(),v.end(),f);
事实是,我相信在调用站点上要创建的lambda对象,这将使它成为这个代码段中的一个临时对象,因为它不存储在任何变量上,而是正在创建和传递一个const引用到std ::函数.如果是这样,那么lambda对象应该已经被破坏了,在f中留下一个悬挂的引用,当std :: count_if使用时会导致未定义的行为.
假设文章没有错,我的心理模型有什么问题?当lambda对象被破坏时?
解决方法
好的,我们从基础开始:上面的代码当然是不合法的,因为它在一些相当基本的方式是不正确的.线
std::function<bool(int)> f(std::cref([n](int i) {return i%n == 0));
最低限度需要写成
std::function<bool(int)> f(std::cref([n](int i) {return i%n == 0;}));
请注意,代码是在Dr.Dobb的文章中写成的,就像在问题中一样,即代码合法的任何陈述都已经很有问题了.
一旦解决了简单的语法错误,下一个问题是std :: cref()是否可以实际用于绑定到rvalue.根据5.1.2 [expr.prim.lambda]第2段(感谢DyP参考),lambda表示显然是一个暂时的.由于将引用绑定到临时文件通常是一个相当糟糕的主意,因此std :: cref()将是规避此限制的一种方式.事实证明,根据20.10 [function.objects]第2段std :: cref()被声明为
template <class T> reference_wrapper<const T> cref(const T&) noexcept; template <class T> void cref(const T&&) = delete; template <class T> reference_wrapper<const T> cref(reference_wrapper<T>) noexcept;
也就是说,即使纠正语法错误,语句也是不正确的. gcc和clang都不编译此代码(我已经使用了两个编译器的相当近期版本及其各自的标准C库).也就是说,基于上述声明,这段代码显然是非法的!
最后,没有什么可以延长上述表达式中的临时性生命周期.临时扩展的唯一原因是它或其一个数据成员立即绑定到[const]引用.围绕临时包装函数调用可以禁止这个终身延期.