我应该复制std::函数还是可以始终引用它? 在我的C++应用程序中(使用VisualStudio 2010),我需要存储一个STD::函数,像这样: 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? }; class-MyClass { 公众: typedef std::function MyFunction; MyClass(Myfunction和Myfunction); 私人: MyFunction m_MyFunction;//我应该使用这个吗? MyFunction&m_MyFunction;//还是应该使用这个? };

我应该复制std::函数还是可以始终引用它? 在我的C++应用程序中(使用VisualStudio 2010),我需要存储一个STD::函数,像这样: 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? }; class-MyClass { 公众: typedef std::function MyFunction; MyClass(Myfunction和Myfunction); 私人: MyFunction m_MyFunction;//我应该使用这个吗? MyFunction&m_MyFunction;//还是应该使用这个? };,c++,lambda,std-function,C++,Lambda,Std Function,如您所见,我在构造函数中添加了函数参数作为引用 但是,在我的类中存储函数的最佳方法是什么 由于std::function只是一个函数指针,并且函数的“可执行代码”保证保留在内存中,我可以将函数存储为引用吗 如果lambda被传递并且调用方返回,我是否需要复制 我的直觉告诉我,存储引用(甚至是常量引用)是安全的。我希望编译器在编译时为lambda生成代码,并在应用程序运行时将此可执行代码保存在“虚拟”内存中。因此,可执行代码永远不会被“删除”,我可以安全地存储对它的引用。但这真的是真的吗?你想

如您所见,我在构造函数中添加了函数参数作为引用

但是,在我的类中存储函数的最佳方法是什么

  • 由于std::function只是一个函数指针,并且函数的“可执行代码”保证保留在内存中,我可以将函数存储为引用吗
  • 如果lambda被传递并且调用方返回,我是否需要复制

我的直觉告诉我,存储引用(甚至是常量引用)是安全的。我希望编译器在编译时为lambda生成代码,并在应用程序运行时将此可执行代码保存在“虚拟”内存中。因此,可执行代码永远不会被“删除”,我可以安全地存储对它的引用。但这真的是真的吗?

你想复制多少就复制多少。它是可复制的。标准库中的大多数算法都要求函子为空

然而,在非平凡的情况下,通过引用传递可能会更快,所以我建议通过常量引用传递并通过值存储,这样您就不必关心生命周期管理。因此:

class MyClass
{
public:
    typedef std::function<int(int)> MyFunction;
    MyClass (const Myfunction &myFunction);
          // ^^^^^ pass by CONSTANT reference.
private:
    MyFunction m_myFunction;    // Always store by value
};
class-MyClass
{
公众:
typedef std::function MyFunction;
MyClass(常量Myfunction和Myfunction);
//^^^^^按常量引用传递。
私人:
MyFunction m_MyFunction;//始终按值存储
};
通过传递常量或右值引用,您可以向调用者保证,在仍然可以调用函数的情况下,您不会修改该函数。这可以防止您错误地修改函数,通常应该避免故意修改,因为它的可读性不如使用返回值

编辑:我最初在上面说的是“常量或右值”,但Dave的评论让我查了一下,右值引用确实不接受左值

由于std::function只是一个函数指针,并且函数的“可执行代码”保证保留在内存中,我可以将函数存储为引用吗

std::function
不仅仅是一个函数指针。它是围绕任意可调用对象的包装器,并管理用于存储该对象的内存。与任何其他类型一样,只有当您有其他方法保证引用对象在使用该引用时仍然有效时,才可以安全地存储引用

除非您有很好的理由存储引用,并且有办法保证它仍然有效,否则请按值存储它


通过
const
引用传递给构造函数是安全的,并且可能比传递值更有效。通过非
const
引用传递是个坏主意,因为它阻止您传递临时对象,因此用户不能直接传递lambda、
bind
的结果或除
std::function
本身之外的任何其他可调用对象。

我建议您复制:

MyFunction m_myFunction; //prefferd and safe!

这是安全的,因为如果原始对象超出了作用域而销毁自身,则副本仍将存在于类实例中。

如果您通过引用将函数传递给构造函数,而不复制它,则当函数超出此对象的作用域时,您将失去运气,因为引用将不再有效。在前面的回答中已经提到了很多

我想补充的是,您可以通过value将函数传递给构造函数,而不是引用。为什么?无论如何,您都需要它的一个副本,因此,如果您通过值传递,编译器可以在传入临时值(例如就地编写的lambda表达式)时优化创建副本的需要

当然,无论您如何操作,当您将传入函数分配给变量时,您可能会创建另一个副本,因此请使用
std::move
消除该副本。例如:

class MyClass
{
public:
   typedef std::function<int(int)> MyFunction;

   MyClass (Myfunction myFunction): m_myfunction(std::move(myFunction))
       {}

private:
   MyFunction m_myFunction;
};
class-MyClass
{
公众:
typedef std::function MyFunction;
MyClass(Myfunction Myfunction):m_Myfunction(std::move(Myfunction))
{}
私人:
MyFunction m_MyFunction;
};
因此,如果它们向上面传递一个右值,编译器将优化第一个副本到构造函数中,而std::move将删除第二个副本:)

如果您的(唯一)构造函数接受常量引用,则无论它是如何传入的,您都需要在函数中复制它

另一种方法是定义两个构造函数,分别处理左值和右值:

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;
};
class-MyClass
{
公众:
typedef std::function MyFunction;
//获取左值并将构造复制到本地变量:
MyClass(常量Myfunction和Myfunction):m_Myfunction(Myfunction)
{}
//获取右值并移动构造本地变量:
MyClass(MyFunction&&MyFunction):m_MyFunction(std::move(MyFunction))
{}
私人:
MyFunction m_MyFunction;
};
现在,您可以以不同的方式处理右值,并通过显式处理(而不是让编译器为您处理)消除在这种情况下复制的需要。可能比第一个稍微更有效,但代码也更多

(可能在这里看到了一些)相关参考(以及非常好的阅读):

作为一般规则(特别是在某些高线程系统中使用这些系统时),按值传递。实际上,无法从线程内部验证底层对象是否仍然存在引用类型,因此您将面临非常严重的争用和死锁错误

另一个需要考虑的问题是std::函数中的任何隐藏状态变量,对于这些变量,修改是非常不可能的