Pat*_*ick 60 c++ lambda std-function
在我的C++应用程序中(使用Visual Studio 2010),我需要存储一个std :: function,如下所示:
class MyClass
{
public:
typedef std::function<int(int)> MyFunction;
MyClass (Myfunction &myFunction);
private:
MyFunction m_myFunction; // Should I use this one?
MyFunction &m_myFunction; // Or should I use this one?
};
Run Code Online (Sandbox Code Playgroud)
如您所见,我在构造函数中添加了函数参数作为引用.
但是,在我的班级中存储该功能的最佳方法是什么?
我的直觉是说存储引用是安全的(甚至是const引用).我希望编译器在编译时为lambda生成代码,并在应用程序运行时将此可执行代码保存在"虚拟"内存中.因此,可执行代码永远不会被"删除",我可以安全地存储对它的引用.但这是真的吗?
Mik*_*our 60
我可以将函数存储为引用,因为std :: function只是一个函数指针,函数的"可执行代码"保证保留在内存中吗?
std::function
不仅仅是一个函数指针.它是任意可调用对象的包装器,并管理用于存储该对象的内存.与任何其他类型一样,仅当您使用其他方式保证引用对象在使用该引用时仍然有效时,才可安全存储引用.
除非您有充分的理由存储引用,并且保证它仍然有效,否则请按值存储它.
通过const
引用传递构造函数是安全的,并且可能比传递值更有效.通过非const
引用传递是一个坏主意,因为它阻止您传递临时,因此用户不能直接传递lambda,结果bind
或除std::function<int(int)>
自身之外的任何其他可调用对象.
jsd*_*sdw 15
如果您通过引用将函数传递给构造函数,并且不复制它,那么当函数超出此对象之外的范围时,您将会失败,因为引用将不再有效.在之前的答案中已经说了很多.
我想要添加的是,您可以通过值而不是引用将函数传递给构造函数.为什么?好吧,无论如何你需要它的副本,所以如果你通过值传递,编译器可以在传入临时值时(例如就地写入的lambda表达式)优化制作副本的需要.
当然,无论你做什么,当你将传入的函数赋给变量时,你可能会制作另一个副本,所以std::move
用来消除那个副本.例:
class MyClass
{
public:
typedef std::function<int(int)> MyFunction;
MyClass (Myfunction myFunction): m_myfunction(std::move(myFunction))
{}
private:
MyFunction m_myFunction;
};
Run Code Online (Sandbox Code Playgroud)
因此,如果它们将rvalue传递给上面的代码,编译器会将第一个副本优化到构造函数中,而std :: move会删除第二个副本:)
如果你的(唯一)构造函数接受一个const引用,你将需要在函数中复制它,而不管它是如何传入的.
另一种方法是定义两个构造函数,分别处理左值和右值:
class MyClass
{
public:
typedef std::function<int(int)> MyFunction;
//takes lvalue and copy constructs to local var:
MyClass (const Myfunction & myFunction): m_myfunction(myFunction)
{}
//takes rvalue and move constructs local var:
MyClass (MyFunction && myFunction): m_myFunction(std::move(myFunction))
{}
private:
MyFunction m_myFunction;
};
Run Code Online (Sandbox Code Playgroud)
现在,您可以不同地进行rvalue,并通过显式处理来消除在这种情况下复制的需要(而不是让编译器为您处理它).可能比第一个更有效,但也是更多的代码.
(可能在这里看到相当多)相关参考(和一个非常好的阅读):http: //cpp-next.com/archive/2009/08/want-speed-pass-by-value/