2012-12-11 30 views
24

domanda principale

Sto cercando di compilare il seguente codice con GCC 4.7.2:catturare una variabile statica per riferimento in C++ 11 lambda

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

E sembra che non sia andando bene, come l'uscita è questa:

$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 

Quindi, la mia prima domanda sarebbe:

Si tratta di un errore di GCC o il codice non è legittimo in C++ 11? È corretto in qualsiasi versione recente di GCC?

Utilizzando il trucco in una fabbrica shared_ptr

considero di costruire un manufatto in base a questo principio, ma utilizzando una variabile statica non letterale. Questo artefatto è pensato per essere una fabbrica di oggetti shared_ptr < T, che evitano la creazione di nuovi oggetti T quando è sufficiente un contenitore shared_ptr duplicato per la stessa istanza.

Questo artefatto sarà simile:

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), 
     [&registry] (Foo* p) { 
      registry.erase(p->getName()); 
      delete p; 
     }); 

    registry.emplace(name,b); 
    return b; 
} 

Per quanto ne so, se il problema GCC discusso in precedenza non è un problema in termini di C++ 11 conformità, questo manufatto non dovrebbe essere un problema o. L'unica cosa da fare attenzione usando questo hack, è di non impostare l'oggetto T_previsto risultante < a qualsiasi oggetto globale che potrebbe essere distrutto dopo la variabile statica.

Ho ragione su questo?

+0

Compila e gira bene su g ++ 4.6.3 – goji

risposta

58

Perché stai anche provando a catturare bar? È statico. Non è necessario catturarlo affatto. Solo le variabili automatiche devono essere catturate. Clang lancia un duro errore sul tuo codice, non solo un avvertimento. E se rimuovi semplicemente lo &bar dalla cattura lambda, allora il codice funziona perfettamente.

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

stampe

0 
1 
2 
+0

Il codice non modificato funziona bene su g ++ 4.6.3 ?? – goji

+1

@Troy: Probabilmente un bug in g ++ 4.6.3 allora. –

+0

Dolce, pensavo che non fosse nello scopo in questa circostanza, grazie. –

11

Per lo standard, è possibile catturare solo le variabili con durata automatica di stoccaggio (o this, che è menzionato come esplicitamente capturable).

Quindi, no, non si può fare che secondo lo standard (o, per rispondere alla tua prima domanda, che non è valido C++ 11 e non è un bug del compilatore)

5.1.1/2 Un nome nella lambda-capture deve essere nel campo di applicazione nel contesto dell'espressione lambda e deve essere questo o fare riferimento a una variabile o riferimento locale con durata di archiviazione automatica.

EDIT: E, come ha detto Kevin, non è nemmeno necessario catturare uno static locale.

Problemi correlati