Dlaczego lambdy mogą być lepiej zoptymalizowane przez kompilator niż zwykłe funkcje?
W swojej książce The C++ Standard Library (Second Edition)
Nicolai Josuttis stwierdza, że lambda mogą być lepiej zoptymalizowane przez kompilator niż zwykłe funkcje.
Dlaczego?Ponadto kompilatory C++ optymalizują lambda lepiej niż zwykłe funkcje. (Strona 213)
Myślałem, że jeśli chodzi o inlining, nie powinno być już żadnej różnicy. Jedynym powodem, dla którego mogłem myśleć jest to, że Kompilatory mogą mieć lepszy lokalny kontekst z lambda i takie mogą tworzyć więcej założeń i wykonać więcej optymalizacji.
2 answers
Powodem jest to, że lambda są obiektami funkcyjnymi , więc przekazanie ich do szablonu funkcji spowoduje utworzenie nowej funkcji specjalnie dla tego obiektu. Kompilator może więc trywialnie wbudować wywołanie lambda.
Dla funkcji, z drugiej strony, stosuje się stare zastrzeżenie: funkcja Wskaźnik jest przekazywana do szablonu funkcji, a Kompilatory tradycyjnie mają wiele problemów z wywołaniem za pomocą wskaźników funkcji. Mogą teoretycznie być inlined, ale tylko wtedy, gdy funkcja otoczenia jest inlined, jak również.
Jako przykład rozważ następujący szablon funkcji:
template <typename Iter, typename F>
void map(Iter begin, Iter end, F f) {
for (; begin != end; ++begin)
*begin = f(*begin);
}
Nazywając to lambdą w ten sposób:
int a[] = { 1, 2, 3, 4 };
map(begin(a), end(a), [](int n) { return n * 2; });
Wyniki tej instancji (stworzonej przez kompilator):
template <>
void map<int*, _some_lambda_type>(int* begin, int* end, _some_lambda_type f) {
for (; begin != end; ++begin)
*begin = f.operator()(*begin);
}
... kompilator zna _some_lambda_type::operator ()
i potrafi wywoływać do niego trywialnie. (I wywołanie funkcji map
z dowolnym innym lambda utworzyłoby nową instancję map
ponieważ każda lambda ma odrębną Typ.)
Ale gdy wywołane ze wskaźnikiem funkcji, instancja wygląda następująco:
template <>
void map<int*, int (*)(int)>(int* begin, int* end, int (*f)(int)) {
for (; begin != end; ++begin)
*begin = f(*begin);
}
... i tutaj f
wskazuje na inny adres dla każdego wywołania do map
i dlatego kompilator nie może wywoływać inline do f
, chyba że wywołanie otaczające do map
zostało również wbudowane tak, że kompilator może rozwiązać f
do jednej konkretnej funkcji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-05 14:03:44
Ponieważ kiedy przekazujesz" funkcję " do algorytmu, w rzeczywistości przekazujesz wskaźnik do funkcji, więc musi ona wykonać pośrednie wywołanie za pomocą wskaźnika do funkcji. Kiedy używasz lambda, przekazujesz obiekt do instancji szablonu specjalnie stworzonej dla tego typu, A wywołanie funkcji lambda jest wywołaniem bezpośrednim, a nie wywołaniem za pomocą wskaźnika funkcji, więc może być znacznie bardziej prawdopodobne, że zostanie zainlinowane.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-11 22:21:33