28

Is there any overhead associated with using lambda expressions in C++0x (under VS2010)?
I know that using function objects incurs overhead, but I'm referring to expressions that are passed to STL algorithms, for example. Does the compiler optimize the expression, eliminating what seems to appear like a function call? I started to really like lambda expressions, but I'm a bit concerned about the speed penalty.

Thanks in advance!

Gratian Lup
  • 1,485
  • 3
  • 19
  • 29
  • 7
    Why are you sure using function objects (functors) incurs overhead? They can be optimized too! The only way to know is to build with full optimizations enabled and then look at the assembly. – EFraim Jul 10 '10 at 10:40
  • When I said function object I was referring to something like boost::function, my fault. I know that classic function objects can be inlined, and I wanted to know if this happens with lambdas too. – Gratian Lup Jul 10 '10 at 10:50
  • ah ok, those do have some overhead. But Lambdas don't (unless you wrap them in a `std::function` object (don't need to use boost, since that has been adopted into the 0x standard – jalf Jul 10 '10 at 11:02

2 Answers2

50

You "know" that function objects incur overhead? Perhaps you should recheck your facts. :)

There is typically zero overhead to using a STL algorithm with a function object, compared with a hand-rolled loop. A naive compiler will have to repeatedly call operator() on the functor, but that is trivial to inline and so in effect, the overhead is zero.

A lambda expression is nothing more than syntactic sugar for a function object. The code is transformed into a function object by the compiler, so it too has zero overhead.

jalf
  • 243,077
  • 51
  • 345
  • 550
  • 5
    Empirically, this is false. Adding a lot of instantiations of `std::functions` significantly increases the size of the executable, at least in VS2010. I just performed this test. – shoosh May 26 '11 at 18:43
  • 8
    @shoosh: So? Adding a lot of instantiations of `std:string` incurs a lot of overhead too. But that wasn't what the question, or my answer, were about. They were about function objects and lambdas. `std::function` is neither. – jalf May 30 '11 at 04:51
  • 9
    just to elaborate, `std::function` is a wrapper class, an abstraction over all callable objects, whether function pointers or functors. And it is not free to use. But if you avoid the wrapper, and just use a functor, or a lambda, directly, there is zero overhead – jalf Aug 30 '12 at 21:12
  • @jalf Excuse my ignorance.. but don't you have to use std::function to declare a function that accepts a lambda as a parameter? – Tomas Andrle Oct 13 '12 at 20:50
  • 1
    @TomA: not exactly. A function template taking some type `T` can take a lambda as a parameter. Of course, for a non-template function, you have to specify the actual parameter type, and you can't do that if the type is a lambda, so in that case, you have to wrap it in a `std::function` or similar. – jalf Oct 14 '12 at 00:55
  • 1
    As jalf said, there is no need to wrap a lambda with std::function. std::function does pay abstraction overhead at runtime, but lambdas do not. Assuming your functors are optimized (ctor and operator() inlined), your lambda expressions do have zero overhead in comparison. Now whether you use lambdas or function objects directly, there *is* an overhead if you want to be able to store them and invoke them at runtime through std::function. – stinky472 Feb 11 '13 at 12:24
20

Under the hood,

void f(char delim)
{
  std::for_each( seq.begin()
               , seq.end()
               , [=](const T& obj){std::cout << obj << delim;} );
}

approximately translates into

class __local_class_name {
  char __delim;
public:
  __local_class_name(char delim) : __delim(delim) {}
  void operator()(const T& obj) {std::cout << obj << __delim;}
};

void f(char delim)
{
  std::for_each( seq.begin()
               , seq.end()
               , __local_class_name(delim) );
}

As with all function objects, the overhead is very minimal, since the call can easily be inlined.

jalf
  • 243,077
  • 51
  • 345
  • 550
sbi
  • 219,715
  • 46
  • 258
  • 445
  • 4
    He does; `[=]` indicates that all local objects should be captured by value. – Dennis Zickefoose Jul 10 '10 at 13:12
  • 1
    @Dennis: Only jalf added the `=`, so @Dario was right. `:(` @jalf: Thanks. My excuse is that I hadn't had the time yet to play with this, so it's all typed from hearsay. – sbi Jul 10 '10 at 14:43
  • 1
    yeah, I should probably have left a comment saying I added it. :) But yeah, `[=]` captures everything by value. We could have used `[delim]` as well, to capture that variable specifically. Btw, I +1'ed your answer. :) – jalf Jul 10 '10 at 15:15
  • __local_class_name would be a local class in the scope of the function f. C++0x allows local class instances to be used as parameters to function templates (they are not allowed current standard). It's also worth noting that the class name is generated by the compiler for each lambda and you can not name the type of the lambda yourself. – snk_kid Jul 10 '10 at 17:57
  • @snk_kid: I was wondering about whether that class would be function-local or not. In the end I decided that, since didn't know, and since the name was supposed to be unique anyway, I would err to the safe side and put it into namespace scope. Can you cite chapter and verse? If so, I'd go and move it. – sbi Jul 10 '10 at 18:19
  • @jalf: No problem about the edit. And I figured that you'd give me an up-vote for this as soon as I saw you around. However, I was first in up-voting you. `:)` – sbi Jul 10 '10 at 18:20
  • how would you go about inlining the call? It seems everywhere I look, people say "the call can easily be inlined", but I don't see how... I mean, it's not like I can write `inline` before the definition of `operator()`, or` I mean all I write is the `[](){return stuff;}` bit, how do I request inlining? – Born2Smile Apr 11 '16 at 03:04