2015-06-23 17 views
8

Durante l'utilizzo di alcuni oggetti lambda locali in una funzione C++ 11, ero tentato di dichiararli come const static auto lambda = ... solo per far sapere al compilatore che c'è un solo oggetto std::function necessario (e possibilmente ottimizzare la chiamata e/o in linea) ma mi sono reso conto che catturare i valori locali per riferimento in questa circostanza porta a comportamenti strani.const static auto lambda utilizzato con acquisizione per riferimento

Si consideri il seguente codice:

void process(const Data& data, const std::function<void(DataElement&>& lambda) { 
    ... 
} 

void SomeClass::doSomething() 
{ 
    int foo = 0; 

    const static auto lambda = [&foo]() { .... ++foo; .... } 

    process(data, lambda); 
} 

Questo non funziona con molteplici invocazioni doSomething() ma i meccanici non è chiaro.

  • Is foo legato alla prima invocazione e poi tenuto legato a un indirizzo di stack, che non è più valido sul invocazioni successive?
  • Sono obbligato a lasciare in questo caso lo static?

Dove è specificato questo comportamento nello standard? Considerando che è una variabile static dove è costruita? Pigramente alla prima chiamata di doSomething() (in modo che la prima invocazione funzioni) o all'avvio del programma?

+1

Ad ogni modo, attualmente, si costruisce 'std :: function' dal lambda ad ogni chiamata. (e la creazione del tuo lambda è leggera). – Jarod42

+0

Perché non 'static int foo = 0;'? Dato che c'è un solo lambda legato a 'pippo', probabilmente non hai bisogno di più copie di' foo'. – MSalters

risposta

12

Una variabile di scope della funzione statica viene inizializzata "pigramente", quando il flusso di controllo raggiunge prima la sua dichiarazione. Ciò significa che l'acquisizione per riferimento effettivamente si associa allo foo attualmente in pila e, al termine della chiamata, tale associazione diventa pendente.

Non cercare di aiutare troppo il compilatore; fare lambdastatic sembra una micro-ottimizzazione, con effetti collaterali molto negativi. Non vi è alcun overhead implicato nella creazione di un oggetto di chiusura e il compilatore può facilmente identificarlo indipendentemente dal fatto che sia static o meno.

Per non parlare del fatto che non si sta salvando sulla creazione dell'oggetto std::function anche con il proprio approccio. Il tipo di espressione lambda è un oggetto di chiusura senza nome, nonstd::function. Quindi, anche se lambda è static, l'oggetto std::function viene creato in ogni chiamata comunque (a meno che l'intera faccenda non sia in linea).

+0

Molto interessante, specialmente l'ultima parte. Potresti approfondire il motivo per cui l'oggetto 'std :: function' deve essere creato in ogni chiamata? Non capisco perché succede ... – JorenHeit

+0

@JorenHeit Perché non è memorizzato nella cache. La variabile statica "mette in cache" l'oggetto di chiusura (la funzione lambda), ma non una 'std :: function'.Una 'std :: function' temporanea viene creata dalla chiamata' process (data, lambda) 'per inizializzare il parametro' lambda' della funzione. – Angew

+0

Giusto ... quindi sarebbe risolto se è dichiarato come 'std :: function' piuttosto che usare auto? – JorenHeit

0

Questo non funziona con invocazioni multiple di doSomething() ma la meccanica non è chiara.

Questo perché foo è allocato nello stack. L'indirizzo esatto di foo dipende dallo stack di chiamate che ha portato all'invocazione di doSomething. In altre parole, è probabile che l'indirizzo di foo sia diverso tra le chiamate di funzioni, a meno che lo stack di chiamate sia esattamente lo stesso.

Problemi correlati