2012-10-03 12 views
23

que tienen una buena cantidad de código que se basa en la captura de un shared_from_this() cuando se utiliza una expresión lambda como llamada de retorno para asegurar que mi caso se mantiene vivo:C++: ¿Se puede optimizar una captura explícita de lambda no utilizada?

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

Así que la pregunta es: ya que no soy referenciando self en el interior el cuerpo lambda, ¿es un compilador compatible que permite optimizar la captura de distancia?


Considere el siguiente programa:

#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; 
} 

la salida es:

1 
2 

Esto indica que g++-4.7.1 no optimiza la captura de distancia (ni tampoco clang-3.1).

Respuesta

30

Las garantías estándar que capturaron valores no están optimizados de distancia (por §5.1.2/14):

Una entidad es capturado por copia si se implícitamente capturado y la captura-default es = o si está explícitamente capturado con una captura que no incluye un &. Para cada entidad capturada por copia, se declara un miembro de datos estáticos no no identificado en el tipo de cierre. El orden de declaración de estos miembros no está especificado. El tipo de dicho miembro de datos es el tipo de la entidad capturada correspondiente si la entidad no es una referencia a un objeto, o el tipo al que se hace referencia de otro modo.

Así, self se copia en el cierre en la evaluación (por §5.1.2/21):

Cuando se evalúa la lambda-expresión, las entidades que son capturados por copia se utilizan para Inicializar directamente cada miembro correspondiente de datos no estáticos del objeto de cierre resultante.

+1

Esto parece contradecir [esta respuesta] (http://stackoverflow.com/questions/6181464/c11-lambda-capture-semantics), que dice que si no se usa ODR entonces no se captura realmente. – GManNickG

+9

@GManNickG: La diferencia es la captura implícita ('[=]') y * explícita * captura ('[someNameHere]'). La captura implícita requiere elementos usados ​​ODR. La captura explícita no. –

+0

@NicolBolas: Gotcha. Una entidad se captura implícitamente si y solo si se usa ODR. En ese punto, está en el mismo bote que las entidades capturadas explícitamente. Gracias. – GManNickG

Cuestiones relacionadas