Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: Can an unused lambda explicit capture be optimized out?

I have a decent amount of code that relies on capturing a shared_from_this() when using a lambda expression as a callback to ensure that my instance stays alive:

std::shared_ptr<Thing> self = shared_from_this(); auto doSomething = [this, self] () {     // various statements, none of which reference self, but do use this } 

So the question is: Since I am not referencing self inside the lambda body, is a conformant compiler allowed to optimize the capture away?


Consider the following program:

#include <functional> #include <iostream> #include <memory>  std::function<void ()> gFunc;  struct S : std::enable_shared_from_this<S> {     void putGlobal()     {         auto self = shared_from_this();         gFunc = [self] { };     } };  int main() {     auto x = std::make_shared<S>();     std::cout << x.use_count() << std::endl;     x->putGlobal();     std::cout << x.use_count() << std::endl; } 

The output is:

1 2 

This indicates that g++-4.7.1 does not optimize the capture away (nor does clang-3.1).

like image 557
Travis Gockel Avatar asked Oct 03 '12 23:10

Travis Gockel


People also ask

Do lambdas go out of scope?

A lambda object must not outlive any of its reference captured objects. Lambda expressions may capture objects with automatic storage duration from the set of enclosing scopes (called the reaching scope) for use in the lambda's function body.

Is lambda capture a const?

By default, variables are captured by const value . This means when the lambda is created, the lambda captures a constant copy of the outer scope variable, which means that the lambda is not allowed to modify them.

How do you capture variables in lambda?

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.


1 Answers

The standard guarantees that captured values are not optimized away (per §5.1.2/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. The declaration order of these members is unspecified. The type of such a data member is the type of the corresponding captured entity if the entity is not a reference to an object, or the referenced type otherwise.

So, self is copied into the closure on evaluation (per §5.1.2/21):

When the lambda-expression is evaluated, the entities that are captured by copy are used to direct-initialize each corresponding non-static data member of the resulting closure object.

like image 168
Travis Gockel Avatar answered Sep 19 '22 18:09

Travis Gockel