我应该复制一个std :: function还是我总能参考它?

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)

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

但是,在我的班级中存储该功能的最佳方法是什么?

  • 我可以将函数存储为引用,因为std :: function只是一个函数指针,函数的"可执行代码"保证保留在内存中吗?
  • 如果传递lambda并且调用者返回,我是否必须复制?

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

Mik*_*our 60

我可以将函数存储为引用,因为std :: function只是一个函数指针,函数的"可执行代码"保证保留在内存中吗?

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

除非您有充分的理由存储引用,并且保证它仍然有效,否则请按值存储它.

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

  • 按值传递给构造函数,然后std :: move进入成员.http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ (7认同)
  • "做不做工作比做一些工作更好 - 去2013年的土着".创建对象(1个工作),通过const ref(无工作),使用(1个工作).创建对象(1个工作),按值传递并移动(1个工作),使用(1个工作).所以在这种情况下,通过const ref传递更好. (4认同)
  • 的确。我只是意识到(感谢您的回答) std::function 是函数指针的包装器,即使函数或 lambda 保留在内存中,它的包装器也不一定是。可能(可能?)编译器在将 lambda 传递给我的构造函数时即时生成一个 std::function,这意味着它确实在调用后消失了。谢谢。 (2认同)
  • @Jagannath你假设所有工作都有相同的成本,这是完全错误的。按值传递然后移动很流行,因为它意味着可以将临时变量移入。通过 `const&amp;` 传递会复制它们。按值传递非临时值仍然会复制(到参数)然后移动。但移动通常比复制便宜,至少在两者的成本都很重要的情况下是如此。因此,当(a)在某些情况下工作量较少,(a)任何额外的工作可能微不足道,(b)真正的绩效时,“先价值后移动”是“3项工作”而不是“2项工作”,这是一个错误的概括性陈述取决于整个计划中通过的内容、比例 (2认同)

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/