Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forcing C++11 lambda to capture a variable

Tags:

c++

c++11

lambda

Suppose copying a variable has a needed side effect. And I want to declare a lambda that copies the variable but doesn't otherwise use the variable. What's the minimum required to do this?

Copiable copyable;

auto lambda1 = [=](){};
auto lambda2 = [copyable](){};
auto lambda3 = [=](){ copyable; }
auto lambda4 = [=](){ volatile copy = copyable; }

lambda1 uses implicit capture, and since the body doesn't mention copyable, I don't believe it actually copies it.

lambda2 uses explicit capture, and it seems according to this, it should capture by copy. Is the compiler allowed to elide the copy? See this for another discussion of this.

lambda3 uses implicit capture but the body mentions copyable. Does this constitute an odr-use of copyable?

lambda4 uses implicit capture and forces another volatile copy. I'm sure this will actually work, but it's doing more copies than the minimum.

Motivating case: I need to run a cleanup after an arbitrary number of lambda calls are completed, possibly in different threads. I can do this by using a std::shared_ptr with a custom deleter that runs the cleanup, and somehow passing this to each lambda. Then when all the shared ptrs go out of scope, the cleanup will run.

Edit: lambda3 and lambda4 were missing the = for implicit capture.

like image 728
Glen Low Avatar asked Sep 11 '14 05:09

Glen Low


People also ask

How do you capture a variable in lambda function?

Much like functions can change the value of arguments passed by reference, we can also capture variables by reference to allow our lambda to affect the value of the argument. To capture a variable by reference, we prepend an ampersand ( & ) to the variable name in the capture.

What is the correct syntax for lambda expression in C++11?

Lambdas can both capture variables and accept input parameters. A parameter list (lambda declarator in the Standard syntax) is optional and in most aspects resembles the parameter list for a function. auto y = [] (int first, int second) { return first + second; };

What does it mean to lambda capture this?

A lambda is a syntax for creating a class. Capturing a variable means that variable is passed to the constructor for that class. A lambda can specify whether it's passed by reference or by value.

What does [&] mean in C++?

It's a lambda capture list and has been defined in C++ from the C++11 standard. [&] It means that you're wanting to access every variable by reference currently in scope within the lambda function.


1 Answers

What's the minimum required to do this?

Explicit capture by value, as in lambda2.

lambda1 uses implicit capture, and since the body doesn't mention copyable, I don't believe it actually copies it.

That's right. Variables are only implicitly captured if they're odr-used within the lambda.

lambda2 uses explicit capture, and it seems according to this, it should capture by copy.

That's right. Any explicitly captured variables will be captured, whether they're used or not. This is what you want to do to ensure your object is captured.

Is the compiler allowed to elide the copy? See this for another discussion of this.

No. If a variable is captured, then it's captured. The link doesn't really "discuss" that; the only answer confirms that this is the case, with the appropriate wording from the standard.

lambda3 uses implicit capture but the body mentions copyable. Does this constitute an odr-use of copyable?

Yes. The definition of odr-use is

A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression and the lvalue-to-rvalue conversion is immediately applied.

and the exception doesn't apply since it isn't constant (and therefore can't appear in a constant expression). (But note that this is ill-formed since there's no default capture.)

lambda4 uses implicit capture and forces another volatile copy. I'm sure this will actually work, but it's doing more copies than the minimum.

Indeed; you're forcing implicit capture by using the value, and forcing an extra copy. That's unnecessary, since lambda2 does what you want.

like image 91
Mike Seymour Avatar answered Sep 29 '22 11:09

Mike Seymour