const static auto lambda используется с захватом по ссылке
При использовании некоторых локальных лямбда-объектов в функции C++11 у меня возникло желание объявить их как const static auto lambda = ...
просто чтобы компилятор знал, что есть только один std::function
нужен объект (и, возможно, оптимизировать вызов и / или встроить его), но я понял, что захват локальных значений по ссылке в этом случае приводит к странному поведению.
Рассмотрим следующий код:
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);
}
Это не работает с несколькими вызовами doSomething()
но механика не понятна.
- Является
foo
привязан при первом вызове, а затем привязан к адресу стека, который становится недействительным при последующих вызовах? - Я вынужден так уронить
static
в этом случае?
Где это поведение указано в стандарте? Учитывая, что это static
переменная где это построено? Лениво при первом вызове doSomething()
(чтобы первый вызов работал) или при запуске программы?
2 ответа
Статическая переменная области действия инициализируется "лениво", когда поток управления впервые достигает своего объявления. Это означает, что захват по ссылке действительно связывает foo
в настоящее время в стеке, и когда вызов завершается, эта привязка становится висячей.
Не пытайтесь слишком помогать компилятору; изготовление lambda
static
выглядит как микрооптимизация, с очень плохими побочными эффектами. Фактически, нет никаких накладных расходов, связанных с созданием объекта замыкания, и компилятор может легко встроить его независимо от того, является ли он static
или нет.
Не говоря уже о том, что вы не экономите на создании std::function
возражать даже с вашим подходом. Тип лямбда-выражения является неназванным объектом замыкания, а не std::function
, Так что даже если lambda
является static
, std::function
В любом случае, объект создается в каждом вызове (если все это не встроено).
Это не работает с несколькими вызовами
doSomething()
но механика не понятна.
Это потому что foo
размещается в стеке. Точный адрес foo
зависит от стека вызовов, который привел к вызову doSomething
, Другими словами, адрес foo
вероятно, будет отличаться между вызовами функций, если только стек вызовов не является точно таким же.