2012-10-03 11 views
23

Ho una discreta quantità di codice che si basa sulla cattura di un shared_from_this() quando si utilizza un'espressione lambda come un callback per assicurare che la mia istanza rimane in vita:C++: È possibile ottimizzare una cattura esplicita lambda non utilizzata?

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

Quindi la domanda è: Dal momento che io non sono REFERENCING self all'interno il corpo lambda, è un compilatore conforme che ha permesso di ottimizzare la cattura?


Si consideri il seguente programma:

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

l'output è:

1 
2 

Questo indica che g++-4.7.1 non ottimizza la cattura di distanza (né clang-3.1).

risposta

30

Le garanzie standard acquisiti i valori non sono ottimizzati distanza (per §5.1.2/14):

Un'entità viene catturato copiando se è implicitamente catturato e la cattura predefinito è = oppure se è esplicitamente catturato con un'acquisizione che non include uno &. Per ogni entità catturata dalla copia, un membro di dati statici non senza nome viene dichiarato nel tipo di chiusura. L'ordine di dichiarazione di questi membri non è specificato. Il tipo di tale membro dati è il tipo dell'entità catturata corrispondente se l'entità non è un riferimento a un oggetto o altrimenti al tipo di riferimento.

Quindi, self viene copiato nella chiusura sulla valutazione (per §5.1.2/21):

Quando il lambda-espressione viene valutata, le entità che vengono catturati dalla copia sono utilizzati per inizializzazione diretta ogni membro di dati non statici corrispondente dell'oggetto di chiusura risultante.

+1

Questo sembra contraddire [questa risposta] (http://stackoverflow.com/questions/6181464/c11-lambda-capture-semantics), che dice che se è inutilizzato ODR, allora non viene effettivamente catturato. – GManNickG

+9

@GManNickG: la differenza è quella di acquisizione implicita ('[=]') e * esplicita * cattura ('[someNameHere]'). L'acquisizione implicita richiede elementi ODR usati. L'acquisizione esplicita no. –

+0

@NicolBolas: Gotcha. Un'entità viene catturata implicitamente se e solo se si utilizza ODR. A quel punto, è nella stessa barca delle entità esplicitamente catturate. Grazie. – GManNickG

Problemi correlati