Live data from Hacker News

The Evolutions of Lambdas in C++14, C++17 and C++20

fluentcpp.com

31–40 of 75 posts

Re: The Evolutions of Lambdas in C++14, C++17 and C++20

#31

Regarding returning lambdas, of course it could be done even in c++11 via std::function.

Problems with std::function:- 1. It can not hold move only callable objects. 2. It heap allocate stored callable object if the object is large enough.

Can you point to better alternate ways or idioms?

Re: The Evolutions of Lambdas in C++14, C++17 and C++20

#32
post #25

i was in a leetcode BS interview a while ago with a googler who thought i could not write code in c++ because i could not remember lambda syntax. i only use maybe 30% of c++ features in my software and have been doing this for over 20 years. it’s only recently i started using lambdas more, but still stay away from them because of the potential hidden allocations.

What kind of hidden allocations?

That are used to hold captured variables and values.

Internally, lambdas are function pointers + the context, and the context may or may not be dynamically allocated depending on how lambdas are used.

Re: The Evolutions of Lambdas in C++14, C++17 and C++20

#33
post #23

> Even if you don’t need to handle several types, this can be useful to avoid repetition and make the code more compact and readable. ... > namespace1::namespace2::namespace3::ACertainTypeOfWidget Deeply nested namespaces are problematic in themselves due to namespace resolution (e.g. see https://abseil.io/tips/130 ), but templates should never be an answer to "my type is too long to type out". You're hurting yoursel…

> templates should never be an answer to "my type is too long to type out"

Eh, in some cases it's a wash.

    std::vector> objects;
    // ...
    auto it = std::find_if(objects.begin(), objects.end(), [](auto& widget) { return widget->x == 1; });
Sure, you could repeat the type `std::unique_ptr` in the lambda, but that's just noise. You don't spell out the types like that either in, say, C#. Yes, compilation time is an epsilon slower, but that consideration loses to readability any time of day. (Otherwise you could just remove all comments and indentation from your code - that also makes compilation faster!)

Re: The Evolutions of Lambdas in C++14, C++17 and C++20

#34
post #22

Earlier quoted context omitted.

I've seen a variation of this bug several times in just the last year: myVariable = 1 if not something_unusual(): myVariablr = 2 return myVariablr This code will work just fine until something_unusual() returns True and then it crashes with UnboundLocalError: local variable 'myVariablr' referenced before assignment This really sucks when it happens during a long-running job. Say for example you're looping through an…

Dynamic languages often benefit from some tool assistance. Both your and GPs experience can happen at the same time: GP is probably using a linter or an IDE (like Pycharm) which will point out that "myVariablr" may be undefined.

If you're returning myVariable instead, that's "fine" - it is always defined.

You might get a warning that myVariabl_r_ is unused, but that's also not a given. The bar for being 'used' is pretty low. For example, in this

  def main():
      x = 10
      l = []
      l.append(x)
      return 5
pyflakes believes both x and l are "used", even though neither affects function return value.

Re: The Evolutions of Lambdas in C++14, C++17 and C++20

#35

Earlier quoted context omitted.

Problems with std::function:- 1. It can not hold move only callable objects. 2. It heap allocate stored callable object if the object is large enough.

Can you point to better alternate ways or idioms?

It's possible to write something like `std::unique_function` (which uniquely owns the stored callable and can be moved but not copied). That's often preferable for storing functors.

Example: https://github.com/facebook/folly/blob/main/folly/docs/Funct...

Re: The Evolutions of Lambdas in C++14, C++17 and C++20

#36

Earlier quoted context omitted.

What kind of hidden allocations?

That are used to hold captured variables and values. Internally, lambdas are function pointers + the context, and the context may or may not be dynamically allocated depending on how lambdas are used.

Internally, lambdas are structs with the "function call" operator overload. Context is done via members of the struct: capture by-value, and the struct copies them and stores its own, capture by reference, and the struct member is a reference. There should be zero heap allocation in any case.

Re: The Evolutions of Lambdas in C++14, C++17 and C++20

#37

Is there any flag in some c++ compiler that forces to you to use the newer features? For example, forbidding non-auto declarations.

There is tooling along those lines. I wouldn't expect to find a tool that forbids non-auto declarations, but there are certainly some that suggest when something could've been auto.

Re: The Evolutions of Lambdas in C++14, C++17 and C++20

#38

Earlier quoted context omitted.

What kind of hidden allocations?

That are used to hold captured variables and values. Internally, lambdas are function pointers + the context, and the context may or may not be dynamically allocated depending on how lambdas are used.

People who think that lambdas may cause heap allocations are confusing lambdas with std::function.

Lambdas are essentially syntactic sugar for an anonymous struct holding references to/copies of captured variables and an operator() method with your code. Not 100% precise, but memory-wise that's how it works (and has to work). No dynamic memory allocation is involved here at all.

If you put a lambda (or any other callable) in a std::function, the std::function will copy that functor object, either into its own small-buffer-optimized in-place storage or (above a certain functor size) into heap-allocated memory.

Re: The Evolutions of Lambdas in C++14, C++17 and C++20

#39

Earlier quoted context omitted.

What kind of hidden allocations?

That are used to hold captured variables and values. Internally, lambdas are function pointers + the context, and the context may or may not be dynamically allocated depending on how lambdas are used.

There is no dynamic allocation at all, unless you assign the lambda to an std::function, in which case it _may_ require dynamic allocation if the size of the captured variables exceed the internal storage capacity (typically 32 bytes) of std::function. There are types (usually called 'function_view') floating around that don't dynamically allocate at all, and that can be used as a cheap alternative when the function is not stored for later use.

Re: The Evolutions of Lambdas in C++14, C++17 and C++20

#40
post #22

Earlier quoted context omitted.

>> in Python the number of times something like this happens Anec-data but I’ve been writing python for 15+ years, I’ve contributed to various popular open source projects. I’ve never seen this in a code review. I’ve certainly never seen this kind of mistake released.

I've seen a variation of this bug several times in just the last year: myVariable = 1 if not something_unusual(): myVariablr = 2 return myVariablr This code will work just fine until something_unusual() returns True and then it crashes with UnboundLocalError: local variable 'myVariablr' referenced before assignment This really sucks when it happens during a long-running job. Say for example you're looping through an…

Those type of errors will be caught by the compiler. It's definitely a problem for python-like languages (but not for compiled languages) because there's no compilation step involved before running the code.
Post reply on HN