[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

lambda expressions (was: Re: error with d28016d16e9a ...)

From: John W. Eaton
Subject: lambda expressions (was: Re: error with d28016d16e9a ...)
Date: Fri, 2 Oct 2020 08:23:33 -0400
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.11.0

On 10/1/20 8:13 PM, Rik wrote:
On 10/01/2020 12:42 PM, John W. Eaton wrote:

We could also decide to always use "[=]" when we need to capture something.  Then all variables that are needed, including "this" will be captured using the default rules for capture by value.

I don't think this is recommended practice.  The temporary anonymous struct that is created to represent the lambda expression will then have an argument in the constructor for every existing variable in the surrounding function.  The compiler *might* then optimize out all of the additional unused captures, but I think it would be better to just capture what you need either by value "[=variable_name]" if small like a built-in type or a pointer or by reference "[&variable_name]" if it is something large like the instance of a class.  For reference, I was using this https://dzone.com/articles/all-about-lambda-functions-in-cfrom-c11-to-c17.

As I understand it, the lambda expression only captures variables that are used. Using a capture default specification actually seems better to me because the variables are already listed in the lambda expression, so explicitly listing them again is redundant. To me, this seems quite similar to using "auto" to avoid writing out something that the compiler can figure out. I don't know why the article you linked lists [=] and [&] as not recommended. I didn't see an explanation and I'm not finding other similar recommendations.

  * when possible, capture variables by value directly in the lambda expression instead of the unwind_action object

I would modify this to only small values should be passed by value.

For unwind-protect to work to save and restore values, they must be copied. You can't just store a reference to a value that you want to restore later. See the attached example.

In Octave, most values are reference counted and relatively cheap to copy anyway.

OTOH, if you mean to use references to objects that are expensive to copy and that are needed in by the lambda expression but that aren't there to be saved/restored, then I agree, it's OK to capture by reference. In that case, it would be nice if you could capture by const reference so you could explicitly say that you won't be modifying the value inside the lambda expression, but I don't see a way to do that without using C++14 features (see https://en.cppreference.com/w/cpp/language/lambda and search for "This also makes it possible to capture by const reference").

Note that

  unwind_action ([] (const auto& x) { use (x); }, x);

is not capturing X by const reference. The unwind_action object only captures by value (copy). Then, when the unwind_action destructor executes, it passes the captured value to the function generated by the lambda expression by const reference. But the unwind_action object still grabbed a copy of X.

The following does capture X by reference

  unwind_action ([&x] () { use (x); });

but it is not const, so it is possible to change to X in the lambda expression function and affect the value of X in the parent scope as well.


Attachment: lambda-tst.cc
Description: Text Data

reply via email to

[Prev in Thread] Current Thread [Next in Thread]