Существуют ли проблемы с производительностью при построении лямбд внутри других функций или циклов? - PullRequest
3 голосов
/ 16 апреля 2019

В JavaScript Mozilla рекомендует , чтобы функции не создавались внутри других функций, если замыкания не нужны, поскольку это отрицательно скажется на производительности скрипта.В JavaScript эта же проблема применима при создании функций внутри циклов.Относится ли такая же проблема к лямбдам C ++?

Например, есть ли разница в производительности между этими двумя функциями:

int f1(vector<int> v) {
    for_each(v.begin(), v.end(), [](int i) { cout << i << endl; });
}

auto print_int = [](int i) { cout << i << endl; };
int f2(vector<int> v) {
    for_each(v.begin(), v.end(), print_int);
}

Я бы предположил, что да, эти проблемы относятся к C ++ и что f2 будет работать лучше, чем f1;однако я не смог найти однозначного ответа.

Ответы [ 4 ]

3 голосов
/ 16 апреля 2019

Нет и да.

Для простых лямбд это не имеет значения.Это потому, что лямбда является простым сокращением для класса с оператором ().

Соответствующим элементом является то, что класс имеет конструктор.Представьте себе:

std::map<std::string, std::string> m = create();
auto lambda = [m]() { /* code */ };

Делать этот захват в цикле не имеет смысла, так как вы копируете много строк, которые не могут быть изменены.В этом случае также может иметь смысл захват по ссылке.

Мой совет: делайте так же, как и в любом другом классе.Если чепо построить, просто разместите его там, где вы найдете логичным.Если построить дорого, подумайте, почему это так дорого, и подумайте о том, чтобы убрать его, когда это возможно.

3 голосов
/ 16 апреля 2019

Нет, в реальных компиляторах не будет разницы в производительности, поскольку компилятор C ++, скорее всего, будет генерировать одинаковый код сборки для обеих функций.

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

1 голос
/ 16 апреля 2019

Это зависит от компилятора или, вернее, от его оптимизатора.

Если он обнаружит, что он может встроить print_int, то производительность f1() и f2() будет одинаковой.

Если этого не произойдет, то f2() может сгенерировать фактический вызов функции (т. е. CALL в ассемблере x86), в то время как f1() может встроить код во избежание вызова функции.

Но очень маловероятно, что "лямбда" будет создана вкаждый проход в любом случае.Лямбда - это просто синтаксический сахар для объекта локального класса с перегруженным оператором вызова функции.

0 голосов
/ 16 апреля 2019

Нет, я ожидаю, что оба примера в вашем коде не изменят скорость.Оба оператора очень похожи для компилятора.

Кроме того, лямбда-выражения могут быть довольно опасной конструкцией в отношении производительности.В зависимости от всей конструкции компилятор может оптимизировать вызов функции более или менее.Использование лямбда-выражений, аналогичных указателям на функции, дает катастрофический результат в производительности, например, использование std::function в качестве оболочки для указателя лямбда-функции (например, Каковы издержки производительности std :: function? )

...