Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda capture reference variable by reference

Tags:

c++

c++11

lambda

For a lambda, I'd like to capture something by reference which was held in the outer scope by reference already. Assume that the referenced value outlives the lambda, but not the scope in which the lamdba gets created.

I know that if a lambda captures a reference variable by value, the referenced object will be copied. I'd like to avoid this copy.

But what happens if I capture a reference variable by reference? What if the original reference variable will get out of scope before executing the lambda? Is this safe? In other words: is the object behind the reference referenced or is the reference variable referenced in the lambda?

auto f() {
    const auto & myRef = g();
    return [&]{ myRef.doSomething(); };
}

f()();  // Safe?
like image 857
leemes Avatar asked Apr 14 '14 18:04

leemes


People also ask

How do you capture variables in lambda?

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.

How many ways are there to capture the external variables in the lambda expression?

In our example, the lambda accesses, or captures, two variables from its enclosing scope: min_wage and upper_limit. There are two ways to capture variables with external references: Capture by copy. Capture by reference.

What does [=] mean in lambda function?

The [=] you're referring to is part of the capture list for the lambda expression. This tells C++ that the code inside the lambda expression is initialized so that the lambda gets a copy of all the local variables it uses when it's created.

What is capture in lambda function?

A lambda expression can refer to identifiers declared outside the lambda expression. If the identifier is a local variable or a reference with automatic storage duration, it is an up-level reference and must be "captured" by the lambda expression.


1 Answers

Yes, the key issue in capturing an object by reference is the lifetime of the referenced object, not the lifetime of any intervening references used to get it. You can think of a reference as an alias rather than an actual variable. (And in the type system, references are treated differently from regular variables.) The reference aliases the original object, and is independent of other aliases used to alias the object (other than the fact that they alias the same object).

=====EDIT=====

According to the answer given to this SO question (pointed out by dyp), it appears that this may not be entirely clear. Throughout the rest of the language, the concept of a "reference to a reference" doesn't make sense and a reference created from a reference becomes a peer of that reference, but apparently the standard is somewhat ambiguous about this case and lambda-captured references may in some sense be secondary, dependent on the stack frame from which they were captured. (The explicit verbiage the SO answer quotes specifically calls out the referenced entity, which would on the face indicate that this usage is safe as long as the original object lives, but the binding mechanism may implicate the capture chain as being significant.)

I would hope that this is clarified in C++14/17, and I would prefer it to be clarified to guarantee legality for this usage. In particular, I think the C++14/17 ability to capture a variable via an expression will make it more difficult to simply capture a scope via a stack-frame pointer and the most sensible capture mechanism would be to generally capture the specific entities individually. (Perhaps a stack-frame-capture could be permitted if an actual local object is captured by reference, since this would result in UB if the lambda is called outside the scope in any event.)

Until we get some clarification, this may not be portable.

like image 156
Adam H. Peterson Avatar answered Oct 19 '22 03:10

Adam H. Peterson