В своей книге The C++ Standard Library (Second Edition)
Николай Йосуттис утверждает, что компилятор может оптимизировать лямбды лучше, чем простые функции.
Кроме того, компиляторы C ++ оптимизируют лямбда-выражения лучше, чем обычные функции. (Стр. 213)
Это почему?
Я думал, что когда дело доходит до встраивания, не должно быть никакой разницы. Единственная причина, о которой я мог подумать, заключается в том, что компиляторы могут иметь лучший локальный контекст с лямбдами, и это может сделать больше предположений и выполнить больше оптимизаций.
c++
optimization
c++11
lambda
compiler-optimization
Стефан Доллберг
источник
источник
Ответы:
Причина в том, что лямбды являются объектами функций, поэтому передача их в шаблон функции создаст новую функцию специально для этого объекта. Таким образом, компилятор может тривиально включить лямбда-вызов.
С другой стороны, к функциям применяется старое предостережение: указатель на функцию передается в шаблон функции, и у компиляторов традиционно возникает много проблем с встраиванием вызовов через указатели на функции. Теоретически они могут быть встроенными, но только если встроенная функция также встроена.
В качестве примера рассмотрим следующий шаблон функции:
Называя это с лямбда как это:
Результаты в этом экземпляре (создан компилятором):
… Компилятор знает
_some_lambda_type::operator ()
и может тривиально вызывать его. (И вызов функцииmap
с любой другой лямбдой создаст новый экземпляр,map
поскольку каждая лямбда имеет отдельный тип.)Но когда вызывается с указателем на функцию, создание экземпляра выглядит следующим образом:
… И здесь
f
указывает на разные адреса для каждого вызова,map
и, таким образом, компилятор не может встроить вызовы,f
если окружающий вызовmap
также не был встроен, так что компилятор может разрешитьf
одну конкретную функцию.источник
std::sort
классический пример этого - использование лямбды вместо указателя на функцию приводит к увеличению производительности в семь раз (возможно, больше, но у меня нет данных!)std::sort
, илиmap
в моем примере) , а сам лямбда. Лямбда обычно маленькая. Другая функция - не обязательно. Мы занимаемся встраиванием вызовов лямбды внутри другой функции.pred
, определение которой видно, и использующая gcc v5.3,std::find_if(b, e, pred)
не встроенаpred
, ноstd::find_if(b, e, [](int x){return pred(x);})
делает это. Clang удается встроить оба, но не производит код так же быстро, как g ++ с лямбда-выражением.Потому что, когда вы передаете «функцию» алгоритму, вы фактически передаете указатель на функцию, поэтому он должен выполнять косвенный вызов через указатель на функцию. Когда вы используете лямбду, вы передаете объект в экземпляр шаблона, специально созданный для этого типа, и вызов лямбда-функции является прямым вызовом, а не вызовом через указатель на функцию, поэтому он может быть встроен.
источник