I'm trying to compile the following code with GCC 4.7.2:
#include <iostream> int foo() { static int bar; return [&bar] () { return bar++; } (); // lambda capturing by reference } int main (int argc, char* argv[]) { std::cout << foo() << std::endl; return 0; }
And it seems that is not going well, as the output is this one:
$p2.cpp: In function ‘int foo()’: $p2.cpp:6:14: warning: capture of variable ‘bar’ with non-automatic storage duration [enabled by default] $p2.cpp:4:16: note: ‘int bar’ declared here
So, my first question would be:
Is this a failure of GCC, or the code is not legit C++11? Is this fixed in any recent version of GCC?
I consider to build an artifact based on this principle but using a non-literal static variable. This artifact is meant to be a factory of shared_ptr< T > objects, which avoid the creation of new T objects when you just need a duplicate shared_ptr container for the same instance.
This artifact would look like:
std::shared_ptr<Foo> create(std::string name) { static std::unordered_map<std::string,std::weak_ptr<Foo>> registry; if (auto it = registry.find(name) != registry.end()) return registry[name].lock(); auto b = std::shared_ptr<Foo>( new Foo(name), [®istry] (Foo* p) { registry.erase(p->getName()); delete p; }); registry.emplace(name,b); return b; }
As far as I know, if the GCC issue discussed before is not a problem in terms of C++11 conformance, this artifact shouldn't be an issue either. The only thing to take care by using this hack, is to not set the resulting shared_ptr< T > object to any global object which could be destructed after the static variable.
Am I right about this?
C++ Lambdas Capture by referenceIf you precede a local variable's name with an & , then the variable will be captured by reference. Conceptually, this means that the lambda's closure type will have a reference variable, initialized as a reference to the corresponding variable from outside of the lambda's scope.
Lambdas always capture objects, and they can do so by value or by reference.
Capture clause A lambda can introduce new variables in its body (in C++14), and it can also access, or capture, variables from the surrounding scope. A lambda begins with the capture clause. It specifies which variables are captured, and whether the capture is by value or by reference.
Creating a Lambda Expression in C++ auto greet = []() { // lambda function body }; Here, [] is called the lambda introducer which denotes the start of the lambda expression. () is called the parameter list which is similar to the () operator of a normal function.
Why are you even trying to capture bar
? It's static. You don't need to capture it at all. Only automatic variables need capturing. Clang throws a hard error on your code, not just a warning. And if you simply remove the &bar
from your lambda capture, then the code works perfectly.
#include <iostream> int foo() { static int bar; return [] () { return bar++; } (); // lambda capturing by reference } int main (int argc, char* argv[]) { std::cout << foo() << std::endl; std::cout << foo() << std::endl; std::cout << foo() << std::endl; return 0; }
prints
0 1 2
Per the standard, you can only capture variables with automatic storage duration (or this
, which is mentioned as explicitly capturable).
So, no, you can't do that as per the standard (or, to answer your first question, that is not valid C++ 11 and is not a compiler bug)
5.1.1/2 A name in the lambda-capture shall be in scope in the context of the lambda expression, and shall be this or refer to a local variable or reference with automatic storage duration.
EDIT: And, as Kevin mentioned, you don't even need to capture a local static
anyways.
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