递归lambda的开销

时间:2013-06-12 13:21:28

标签: recursion c++11 lambda

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

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; 
}

3 个答案:

答案 0 :(得分:4)

使用lambdas 递归将其存储为std::function会产生开销,尽管它们本身基本上是函子。似乎gcc无法很好地优化,直接comparison可以看到。

实现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);
}

对于我创建的示例,仿函数看起来像second demo

即使有人引入了对std::rand等不纯函数的调用,但没有递归 lambda或使用自定义函数的性能仍然更好。这是一个third demo

结论:使用std::function会产生开销,但根据用例可能会忽略不计。由于此用法会阻止某些编译器优化,因此不应广泛使用它。

答案 1 :(得分: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);
}

很少有足够紧密的递归,因此虚拟方法查找是一个重要的开销,但根据您的应用领域,它当然是可能的。

答案 2 :(得分:2)

C ++中的Lambdas等同于函子,因此调用编译器自动创建的某个类的operator()是一样的。捕获环境时,幕后发生的事情是捕获的变量将传递给类的构造函数并存储为成员变量。

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

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

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

编辑:

经过一些研究并感谢Stefan的回答和代码,结果发现由于std :: function惯用法,递归 lambdas会产生开销。由于lambda必须包装在std :: function上才能调用自身,因此它涉及调用 添加开销的虚函数。

受访者对此答案的评论进行了处理: https://stackoverflow.com/a/14591727/1112142