W swojej książce The C++ Standard Library (Second Edition)
Nicolai Josuttis stwierdza, że kompilator może lepiej zoptymalizować lambdy niż zwykłe funkcje.
Ponadto kompilatory C ++ optymalizują lambdy lepiej niż zwykłe funkcje. (Strona 213)
Dlaczego?
Pomyślałem, że jeśli chodzi o inlining, nie powinno już być żadnej różnicy. Jedynym powodem, dla którego mogłem wymyślić, jest to, że kompilatory mogą mieć lepszy kontekst lokalny z lambdami, a takie mogą przyjmować więcej założeń i wykonywać więcej optymalizacji.
c++
optimization
c++11
lambda
compiler-optimization
Stephan Dollberg
źródło
źródło
Odpowiedzi:
Powodem jest to, że lambdy są obiektami funkcyjnymi, więc przekazanie ich do szablonu funkcji utworzy wystąpienie nowej funkcji specjalnie dla tego obiektu. Kompilator może więc w trywialny sposób wbudować wywołanie lambda.
Z drugiej strony, w przypadku funkcji obowiązuje stare zastrzeżenie: wskaźnik funkcji jest przekazywany do szablonu funkcji, a kompilatory tradycyjnie mają wiele problemów z wbudowywaniem wywołań za pomocą wskaźników funkcji. Oni mogą być teoretycznie inlined, ale tylko wtedy, gdy funkcja jest otaczająca inlined również.
Jako przykład rozważ następujący szablon funkcji:
Nazywając to lambdą w ten sposób:
Wyniki w tej instancji (utworzone przez kompilator):
… Kompilator zna
_some_lambda_type::operator ()
i może wbudowane wywołania do niego w trywialny sposób. (I wywołanie funkcjimap
z dowolnego innego lambda by utworzyć nowy instancji zmap
ponieważ każdy lambda ma inny typ).Ale gdy jest wywoływana ze wskaźnikiem funkcji, instancja wygląda następująco:
... i tu
f
wskazuje na inny adres dla każdego wywołaniamap
, a więc kompilator nie może inline wywołaniaf
chyba otaczający wywołaniemap
zostało również inlined tak, że kompilator może rozwiązaćf
do jednej konkretnej funkcji.źródło
std::sort
to klasyczny przykład tego, że użycie lambd zamiast wskaźnika do funkcji daje tutaj siedmiokrotny (prawdopodobnie więcej, ale nie mam na ten temat danych!) wzrost wydajności.std::sort
, czymap
w moim przykładzie), a sama lambda. Lambda jest zwykle mała. Druga funkcja - niekoniecznie. Zajmujemy się wbudowywaniem wywołań lambda wewnątrz innej funkcji.pred
której definicja jest widoczna, i używając gcc v5.3,std::find_if(b, e, pred)
nie jest wbudowywanapred
, alestd::find_if(b, e, [](int x){return pred(x);})
tak. Clangowi udaje się wstawić oba, ale nie tworzy kodu tak szybko jak g ++ z lambda.Ponieważ kiedy przekazujesz „funkcję” do algorytmu, w rzeczywistości przekazujesz wskaźnik do funkcji, więc musi on wykonać pośrednie wywołanie przez wskaźnik do funkcji. Kiedy używasz lambdy, przekazujesz obiekt do instancji szablonu specjalnie utworzonej dla tego typu, a wywołanie funkcji lambda jest bezpośrednim wywołaniem, a nie wywołaniem przez wskaźnik funkcji, więc jest bardziej prawdopodobne, że może być wbudowane.
źródło