8

与常规递归函数相比,递归 lambda 函数是否会产生任何开销(因为我们必须将它们捕获到 std::function 中)?
此功能与仅使用常规功能的类似功能有什么区别?

int main(int argc, const char *argv[])
{
    std::function<void (int)> helloworld = [&helloworld](int count) {
        std::cout << "Hello world" << std::endl;
        if (count > 1) helloworld(--count);
    }; 
    helloworld(2);
    return 0; 
}
4

3 回答 3

6

通过将 lambda存储为 a来递归使用 lambda 存在开销std::function,尽管它们本身基本上是函子。好像gcc不能很好的优化,直接对比就可以看出。

实现 lambda 的行为,即创建一个仿函数,可以gcc再次优化。您的 lambda 的具体示例可以实现为

struct HelloWorldFunctor
{
   void operator()(int count) const
   {
      std::cout << "Hello world" << std::endl;
      if ( count > 1 )
      {
         this->operator()(count - 1);
      }
   }
};
int main()
{
   HelloWorldFunctor functor;
   functor(2);
}

对于我创建的例子,仿函数看起来就像在第二个演示中一样。

即使引入了对诸如 等不纯函数的调用std::rand,没有递归lambda 或使用自定义函子的性能仍然更好。这是第三个演示

结论:使用 astd::function会产生开销,尽管根据用例的不同,它可能可以忽略不计。由于这种用法会阻止一些编译器优化,因此不应广泛使用。

于 2013-06-12T14:46:40.900 回答
3

所以std::function是多态实现的。这意味着您的代码大致相当于:

struct B
{
    virtual void do(int count) = 0;
};

struct D
{
    B* b;
    virtual void do(int count)
    {
        if (count > 1)
            b->do(count--);
    }
};

int main()
{
    D d;
    d.b = &d;
    d.do(10);
}

很少有足够紧密的递归使得虚拟方法查找是一个很大的开销,但根据您的应用程序领域,这当然是可能的。

于 2013-06-12T16:57:46.690 回答
2

C++ 中的 Lambda 等效于函子,因此它与调用编译器自动创建的某个类的 operator() 相同。当您捕获环境时,幕后发生的事情是那些捕获的变量被传递给类的构造函数并存储为成员变量。

所以简而言之,性能差异应该非常接近于零。

这里有一些进一步的解释:

跳转到“如何实现 Lambda 闭包?”部分 http://www.cprogramming.com/c++11/c++11-lambda-closures.html

编辑:

经过一些研究并感谢 Stefan 的回答和代码,事实证明,由于 std::function 惯用语,递归lambda 存在开销。由于 lambda 必须包装在 std::function 上才能调用自身,因此它涉及调用一个确实会增加开销的虚函数。

该主题将根据此答案的评论进行处理: https ://stackoverflow.com/a/14591727/1112142

于 2013-06-12T13:38:58.610 回答