hov*_*ovo 11 c++ lambda function c++11
你能解释为什么这段代码崩溃了吗?我期望输出"a",但我得到分段错误.
#include <functional>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
struct MyStruct {
vector<string> a;
vector<string> b;
};
void out_data(const MyStruct& my_struct, const std::function<const vector<string>&(const MyStruct&)> getter) {
cout << getter(my_struct)[0] << endl;
}
int main(int argc, char** argv)
{
MyStruct my_struct;
my_struct.a.push_back("a");
my_struct.b.push_back("b");
out_data(my_struct, [](const MyStruct& in) {return in.a;});
return 0;
}
Run Code Online (Sandbox Code Playgroud)
Vit*_*meo 18
该
[](const MyStruct& in) {return in.a;}
Run Code Online (Sandbox Code Playgroud)
lambda表达式相当于
[](const MyStruct& in) -> auto {return in.a;}
Run Code Online (Sandbox Code Playgroud)
返回的副本in.a.std::function然后,您的签名将返回对本地对象的悬空引用.
将lambda表达式更改为
[](const MyStruct& in) -> const auto& {return in.a;}
Run Code Online (Sandbox Code Playgroud)
返回一个const&,修复段错误.
另外,std::function除非你有充分的理由这样做,否则不要用来传递lambda.我建议阅读我关于这个主题的文章:"将函数传递给函数".
我责怪std::function(和你)。当然,我责怪你要求std::function返回悬空引用,正如维托里奥·罗密欧所解释的那样。但我也责怪std::function的构造函数模板没有检查这种情况,在大多数或所有情况下,这种情况应该在编译时可检测到,并因此生成诊断。(我使用“责备”这个词只是为了指出可能需要改进的地方。从这个意义上说,我也责怪自己没有考虑在我自己的unique_function类模板的实现中添加这个精确的检查。)
让我们仔细看看构造函数的签名。我为此目的选择了定义站点。
template<typename R, typename... Args>
template<typename F>
std::function<R(Args...)>::function(F f);
Run Code Online (Sandbox Code Playgroud)
这里应该可以禁止悬挂引用。operator()当且仅当R是对 所返回的临时对象的引用时,才会从 中返回悬空引用F。让我们定义(在构造函数主体的范围内):
using RF = decltype(f(std::forward<Args>()...));
Run Code Online (Sandbox Code Playgroud)
function现在我们几乎可以肯定,将从 的if返回一个悬空引用operator():
std::is_reference<R>::value && ! std::is_reference<RF>::value
Run Code Online (Sandbox Code Playgroud)
但有一个问题,那就是RF类类型可能带有用户定义的转换运算符R。尽管这种转换可能仍然不安全,但我们目前没有足够的信息来做出决定,并且应该在一般性方面犯错误。显然,我们可以检测 的目标是否R是 的公共基类RF(假设上述条件为真):
std::is_convertible<RF *, typename std::remove_reference<R>::type *>::value
Run Code Online (Sandbox Code Playgroud)
我在这里只允许公共继承,因为std::function只能访问公共非二义基类。除非有人出于某种奇怪的原因做了一些std::function事情。(由于转换可以在包装的函数对象内部完成,因此可能不需要这样做。)friendRF
将它们放在一起并反转逻辑,我们可以在function构造函数的主体前面加上以下前缀:
using RF = decltype(f(std::forward<Args>()...));
static_assert( ! std::is_reference<R>::value ||
std::is_reference<RF>::value ||
! std::is_convertible<RF *, typename std::remove_reference<R>::type *>::value,
"Using this function object would result in a dangling reference in the function call" );
Run Code Online (Sandbox Code Playgroud)