Squ*_*all 7 c++ lambda closures c++11
有两种方法可以使用lambda函数变量:
std::function<int(int, int)> x1 = [=](int a, int b) -> int{return a + b;};
//usage
void set(std::function<int(int, int)> x);
std::function<int(int, int)> get();
Run Code Online (Sandbox Code Playgroud)
和:
std::function<int(int, int)>* x2 = new std::function<int(int, int)>([=](int a, int b) -> int{return a + b;});
//usage
void set(std::function<int(int, int)>* x);
std::function<int(int, int)>* get();
Run Code Online (Sandbox Code Playgroud)
我想知道有什么不同,因为我不知道lambda函数数据是如何存储的.
我想知道在性能,内存使用和传递lambda函数作为参数或返回lambda函数的最佳方法方面的最佳方法.
如果lambda函数对象的大小大于4,或者为了避免错误(如果在执行归因时执行某种复制构造函数或者在我不需要时执行某种析构函数),我更喜欢使用指针.
我该如何声明lambda函数变量?
编辑
我想避免复制和移动,我想继续再次使用相同的功能.
我应该如何改变这个例子?
int call1(std::function<int(int, int)> f){
return f(1, 2);
}
int call2(std::function<int(int, int)> f){
return f(4, 3);
}
std::function<int(int, int)>& recv(int s){
return [=](int a, int b) -> int{return a*b + s;};
}
int main(){
std::function<int(int, int)> f1, f2;
f1 = [=](int a, int b) -> int{return a + b;};
f2 = recv(10);
call1(f1);
call2(f1);
call1(f2);
call2(f2);
}
Run Code Online (Sandbox Code Playgroud)
我无法在函数recv中返回引用:
warning: returning reference to temporary
Run Code Online (Sandbox Code Playgroud)
这是一个好的解决方案吗?
int call1(std::function<int(int, int)>* f){
return (*f)(1, 2);
}
int call2(std::function<int(int, int)>* f){
return (*f)(4, 3);
}
std::function<int(int, int)>* recv(int s){
return new std::function<int(int, int)>([=](int a, int b) -> int{return a*b + s;});
}
int main(){
std::function<int(int, int)> f1 = [=](int a, int b) -> int{return a + b;};
std::function<int(int, int)> *f2 = recv(10);
call1(&f1);
call2(&f1);
call1(f2);
call2(f2);
delete f2;
}
Run Code Online (Sandbox Code Playgroud)
编辑(结论)
lambda函数对象就像任何类的实例对象一样.分配,论据和归属的规则是相同的.
Naw*_*waz 18
创建指针是没有意义的std::function.它对你没有任何好处.而不是好处,它会给你带来更多的负担,因为你要删除内存.
所以第一个版本(即非指针版本)就是你应该去的所有东西.
一般来说,像经验法则,尽可能避免 new.
此外,std::function每次使用lambda时都不需要.很多时候,你可以使用auto:
auto add = [](int a, int b) { return a + b;};
std::cout << add(100,100) << std::endl;
std::cout << add(120,140) << std::endl;
Run Code Online (Sandbox Code Playgroud)
你已经明确表示要使用指针了.所以......那样做.
但至少使用智能指针.正确使用std::shared_ptr会阻止一些问题.当然,你必须确保避免循环引用,但对于lambdas,这似乎不太可能.
当然,这仍然是一个糟糕的主意.但是,在完成毫无意义的过早优化意义上,让自己感觉更好的传递方式,而不是在代码的实际运行时间内获得任何实际可测量的好处,这只是可怕的.至少使用a shared_ptr,您不太可能意外删除内存或遇到异常安全问题.
我将忽略糟糕的C++实践,即堆分配你可以轻松堆栈分配的东西,以及在不使用智能指针的情况下跟踪这个内存的痛苦.这将假设您知道自己在做什么,而是专注于您询问的"性能"和"内存使用"问题.
不要认为这是对你想要做的事情的认可.
std::function通常通过对某个对象进行内部堆分配来实现; 由于类型擦除,这是必要的.所以它的大小至少是一个指针; 可能更多.堆分配的大小可能是vtable指针+ lambda类的大小.它的大小取决于你捕获的东西数量以及价值或参考价值.
像大多数C++标准库对象一样,std::function是可复制的.执行副本实际上会复制它,而不是做一个假装副本,你现在有两个具有相同指针的对象.因此每个人都将拥有内部堆对象的独立副本.也就是说,复制它将意味着进行另一个堆分配.这也将复制lambda本身,这意味着复制在其中捕获的所有内容.
但是,像大多数C++标准库对象一样,std::function是可移动的.这并没有做任何内存分配任何责任.
因此,如果你想这样做,它很便宜:
std::function<int(int, int)> x1 = [=](int a, int b) -> int{return a + b;};
//usage
void set(std::function<int(int, int)> x);
const std::function<int(int, int)> &get();
set(std::move(x1)); //x1 is now *empty*; you can't use it anymore.
Run Code Online (Sandbox Code Playgroud)
您的set功能可以根据需要将其移动到自己的内部存储中.注意,get现在返回一个const&; 这取决于这些功能的存储空间无处可去.
会有多便宜move?它可能相当于仅复制字段std::function,以及消隐或以其他方式中和原始字段.除非您处于性能关键代码中,否则这不是您应该关注的任何内容.