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 в настоящее время в стеке, и когда вызов завершается, эта привязка становится висячей.

Не пытайтесь слишком помогать компилятору; изготовление lambdastatic выглядит как микрооптимизация, с очень плохими побочными эффектами. Фактически, нет никаких накладных расходов, связанных с созданием объекта замыкания, и компилятор может легко встроить его независимо от того, является ли он static или нет.

Не говоря уже о том, что вы не экономите на создании std::function возражать даже с вашим подходом. Тип лямбда-выражения является неназванным объектом замыкания, а не std::function, Так что даже если lambda является static, std::function В любом случае, объект создается в каждом вызове (если все это не встроено).

Это не работает с несколькими вызовами doSomething() но механика не понятна.

Это потому что foo размещается в стеке. Точный адрес foo зависит от стека вызовов, который привел к вызову doSomething, Другими словами, адрес foo вероятно, будет отличаться между вызовами функций, если только стек вызовов не является точно таким же.

Другие вопросы по тегам