C++0x Lambda overhead
Asked Answered
E

2

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!

Endear answered 10/7, 2010 at 10:38 Comment(3)
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.Whitebook
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.Endear
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 standardRetinitis
R
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.

Retinitis answered 10/7, 2010 at 10:48 Comment(6)
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.Lise
@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.Retinitis
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 overheadRetinitis
@jalf Excuse my ignorance.. but don't you have to use std::function to declare a function that accepts a lambda as a parameter?Lorant
@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.Retinitis
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.Pliam
O
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.

Octroi answered 10/7, 2010 at 10:44 Comment(7)
He does; [=] indicates that all local objects should be captured by value.Noblesse
@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.Octroi
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. :)Retinitis
__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.Cavalcade
@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.Octroi
@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. :)Octroi
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?Styrene

© 2022 - 2024 — McMap. All rights reserved.