Подтвердить что ты не робот

GCC неправильно отображает глобальные переменные по ссылке в лямбда-функциях?

Кажется, что GCC неправильно отображает глобальные переменные по ссылке в лямбда-функциях, даже если они указаны как "захват по значению". Этот код будет компилировать и печатать "a = 9":

#include <iostream>

int a = 10;

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

Пока этот код не будет компилироваться:

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

Но явно фиксируя глобальное значение по значению, а затем присваивая ему, появляется ошибка:

#include <iostream>

int a = 10;

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

Я уверен, что ошибка - правильное поведение - почему неявный захват обходит эту ошибку? Я просто изучаю новые возможности С++ 11 и случайно написал первый фрагмент кода (не понимая, что это должна быть ошибка), и затем был удивлен, когда изменения в том, что я предположил, были локальной переменной, повлияли на глобальную.

Так как ошибка должна быть назначена переменной захваченного значения в лямбда, GCC предположительно использует ссылку на переменную для целей оптимизации, по крайней мере в этом случае, и не обнаруживает ошибочное назначение.

4b9b3361

Ответ 1

§5.1.2/11:

Если * lambda-expression (имеет связанный с захватом-умолчанию и его составной оператор odr-использует (3.2) this или переменную с продолжительностью автоматического хранения и объект, использующий odr явно не захвачен, то объект, использующий odr, считается неявным захватом,...

Глобальные переменные имеют статическую продолжительность хранения (§3.7.1), поэтому глобальный a не будет неявно зафиксирован по значению. Тем не менее, вы можете получить доступ к глобальной переменной где угодно, поэтому

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

установит глобальный a в 9, как ожидалось.

Явно захватить глобальную должна быть ошибка или UB, потому что в §5.1.2/10 говорится

Идентификаторы в списке захвата просматриваются с использованием обычных правил для поиска неквалифицированных имен (3.4.1); каждый такой поиск найдет переменную с автоматической продолжительностью хранения, объявленной в области охвата локального выражения лямбда.