Given the following sample code:
int main()
{
int i;
auto f = [=]()mutable->int*
{
return &i;
};
return 0;
}
My understanding of lambdas is that the compiler will generate a functor class. That functor class will have members for all copied variables (i
in the example). I believe that in the context of my code, as long as f
exists, it is safe to return the address of one of its members. It seems to me that all compilers got it wrong. I think a warning about using the address of f
's member i
after f
goes out of scope is valid, but the warnings about the "local variable 'i'" are incorrect/misleading. Am I right?
Yes, you're right. The &
operator is applying to the member, not the local object.
Demonstration is straightforward: just modify your example to output the addresses.
#include <iostream>
int main() {
int i;
std::cout << & i << '\n';
std::cout << [=]() mutable -> int * {
return & i;
} () << '\n';
}
http://ideone.com/OqsDyg
Incidentally, this compiles with no warnings under -Wall
in GCC 4.9.
Some terminology:
=
or &
inside [&](){ /*..*/ }
is called a capture-default.(void)some_variable
or int x = some_variable, 5;
) and it doesn't occur in a constant expression.{
statements }
[expr.prim.lambda]/3
The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called the closure type — whose properties are described below.
/11
If a lambda-expression has an associated capture-default and its compound-statement odr-uses (3.2)
this
or a variable with automatic storage duration and the odr-used entity is not explicitly captured, then the odr-used entity is said to be implicitly captured;
Therefore, i
is implicitly captured.
/14
An entity is captured by copy if it is implicitly captured and the capture-default is
=
or if it is explicitly captured with a capture that does not include an&
. For each entity captured by copy, an unnamed non-static data member is declared in the closure type.
There is a non-static data member (of type int
) in the closure type.
/17
Every id-expression that is an odr-use (3.2) of an entity captured by copy is transformed into an access to the corresponding unnamed data member of the closure type.
We don't even need to interpret this, as this paragraph provides us with an example very similar to the OP's:
void f(const int*);
void g() {
const int N = 10;
[=] {
int arr[N]; // OK: not an odr-use, refers to automatic variable
f(&N); // OK: causes N to be captured; &N points to the
// corresponding member of the closure type
};
}
If we apply this to the OP's example, we see that &i
refers to the internal non-static data member of the closure type. Whether or not the diagnostic message is appropriate is not specified in the Standard ;)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With