2012-02-08 13 views
12

GCC parece capturar incorrectamente variables globales por referencia en funciones lambda, incluso cuando se especifican como 'captura por valor'. Este código se compilará e imprimir "a = 9":¿GCC captura incorrectamente variables globales por referencia en funciones lambda?

#include <iostream> 

int a = 10; 

int main() 
{ 
    [=]() { a = 9; }(); 
    std::cout << "a = " << a << std::endl; 
    return 0; 
} 

Mientras que este código no se compilará:

#include <iostream> 

int main() 
{ 
    int a = 10; 
    [=]() { a = 9; }(); // error: assignment of member 'main()::<lambda()>::a' in read-only object 
    std::cout << "a = " << a << std::endl; 
    return 0; 
} 

Pero capturar explícitamente un mundial por su valor y luego asignar a ella le da el error:

#include <iostream> 

int a = 10; 

int main() 
{ 
    [a]() { a = 9; }(); // assigment of read-only object 
    std::cout << "a = " << a << std::endl; 
    return 0; 
} 

Estoy bastante seguro de que el error es el comportamiento correcto, ¿por qué la captura implícita elude este error? Solo estoy explorando las nuevas características de C++ 11 y accidentalmente escribí el primer fragmento de código (sin darme cuenta de que debería ser un error) y luego me sorprendí cuando las modificaciones a lo que asumí que era una variable local afectaron al global.

Dado que debe ser un error asignar una variable capturada por valor en una lambda, GCC presumiblemente utiliza una referencia a la variable para fines de optimización, al menos en este caso, y no detecta la asignación errónea .

+1

VS2010 se comporta de la misma manera en todas las cuentas. Es inusual que dos implementaciones tengan errores exactamente de la misma manera, así que creo que esto puede no ser un error. –

+6

Aquí no está capturando, solo se pueden capturar las variables con almacenamiento automático (y 'this'). Simplemente estás usando un global como global, nada especial sobre lambdas en este contexto. – ildjarn

Respuesta

24

§5.1.2/11:

If a *lambda-expression(has an associated capture-default and its compound-statement odr-uses (3.2) this or a variable with automatic storage duration and the odr-used entity is not explicitly captured, then the odr-used entity is said to be implicitly captured; ...

Las variables globales tienen una duración de almacenamiento estático (§3.7.1), por lo que el mundial a no habrá implícitamente capturado por valor. Aún así, puede acceder a una variable global en cualquier lugar, por lo

[=]() { a = 9; }(); 

establecerá el mundial a a 9 como se esperaba.

explícitamente la captura de un mundial debe haber un error o UB, porque §5.1.2/10 dice

The identifiers in a capture-list are looked up using the usual rules for unqualified name lookup (3.4.1); each such lookup shall find a variable with automatic storage duration declared in the reaching scope of the local lambda expression.