3

In JavaScript, Mozilla recommends that functions should not be created inside other functions if closures are not needed, as it will negatively affect script performance. In JavaScript, this same concern is applicable when creating functions inside of loops. Does the same concern apply to C++ lambdas?

For example, is there a performance difference between these two functions:

int f1(vector<int> v) {
    for_each(v.begin(), v.end(), [](int i) { cout << i << endl; });
}

auto print_int = [](int i) { cout << i << endl; };
int f2(vector<int> v) {
    for_each(v.begin(), v.end(), print_int);
}

I would assume yes, these concerns apply to C++ and that f2 will perform better than f1; however, I haven't been able to find a definite answer.

johnnyodonnell
  • 1,838
  • 3
  • 16
  • 34
  • 1
    Most lambdas (including this one) are trivial structs, so any decent compiler will elide the construction entirely. – Cruz Jean Apr 16 '19 at 18:28
  • 1
    Unlike the other languages all of this stuff gets optimized away at compile time. Lambdas are really just syntactic sugar. If you are really concerned then you can benchmark it using [this](http://quick-bench.com/) – NathanOliver Apr 16 '19 at 18:29

4 Answers4

3

No, there will be no performance difference in real life compilers, as the C++ compiler will likely produce exactly the same assembly code for both functions.

Generally you should not be applying guidelines designed for scripting languages to compiled languages, as they differ a lot in what happening at compilation stage (and thus has no bearing on run-time performance) vs what is happening at run time.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
3

No and yes.

For simple lambdas, it doesn't matter. This because a lambda is a simple shorthand for a class with operator().

The relevant element is that the class has a constructor. Imagine:

std::map<std::string, std::string> m = create();
auto lambda = [m]() { /* code */ };

Doing this capture in a loop doesn't make sense as you copy a lot of strings which should not be able to change. In this case capture by reference might also make sense.

My advice would be: do the same as every other class. If cheep to construct, just place it where you find logical. If expensive to construct, think about why it's that expensive and consider moving it out when possible.

JVApen
  • 11,008
  • 5
  • 31
  • 67
1

It depends on the compiler, or, rather, its optimizer.

If it picks up that it can inline print_int, then the performance of f1() and f2() will be the same.

If it doesn't, then, f2() might generate an actual function call (ie CALL in x86 assembler), while f1() might inline the code avoiding the function call.

But, it's highly unlikely that the "lambda" would be created in each pass in any case. Lambda is just syntax sugar for an object of a local class with overloaded function call operator.

srdjan.veljkovic
  • 2,468
  • 16
  • 24
  • 1
    I am yet to see a compiler inlining the first version, but not the second, or vice versa. – SergeyA Apr 16 '19 at 18:27
  • @SergeyA Me too, but it's possible. Playing around, I did get some differences in generated code on some compilers and optimization levels. Though I got differences in (lack of) optimization of `for_each()` rather than the lambda itself. – srdjan.veljkovic Apr 16 '19 at 18:45
0

No, I would expect that both examples in your code will not make any change in speed. Both statements are quite similar for the compiler.

Also, lambdas can be a quite dangerous construct regarding performance. Depending on the whole construct, the compiler can optimize the function call more or less. Using lambdas similar as function pointers give you a catastrophic result in performance, so for example using std::function as wrapper for a lambda function pointer (e.g. What is the performance overhead of std::function?)

user287107
  • 9,286
  • 1
  • 31
  • 47