2013-04-10 14 views
31

Czy można/wykonuje funkcje wbudowanej kompilacji lambda, aby zwiększyć wydajność, tak jak w przypadku prostych standardowych funkcji?Czy lambdas jest wbudowane jak funkcje w C++?

np.

std::vector<double> vd; 
std::for_each(vd.begin(), vd.end(), [](const double d) {return d*d;}); 

Czy występuje utrata wydajności spowodowana brakiem optymalizacji?

Drugie pytanie: gdzie mogę sprawdzić, czy używany kompilator ma zoptymalizowane wywołania funkcji wbudowanych, które są wysyłane do algorytmu? Mam na myśli to, że jeśli funkcja - nie obiekt funkcji - jest wysyłana do algorytmu, ostatnia dostaje wskaźnik do funkcji, a niektóre kompilatory optymalizują wskaźniki do funkcji inline, a inne nie.

+4

Niektóre są zoptymalizowane, inne nie są, tak jak inne wywołania funkcji. Jeśli jesteś zainteresowany konkretnym połączeniem, musisz sprawdzić, co konkretny kompilator robi z tym konkretnym połączeniem. –

+2

Tu mylą się pojęcia. Wszystkie lambdy są inline. Nie wszystkie połączenia z nimi są konieczne. –

+0

Nie sądzę, aby lambda mogła być wstawiona, jeśli jest przekazywana do funkcji zewnętrznej. – nobar

Odpowiedz

26

W prostych przypadkach, jak twój przykład należy oczekiwać lepszych wyników z lambdas niż ze wskaźników funkcji, zobaczyć

Why can lambdas be better optimized by the compiler than plain functions?

Jak inni już wspomniano, nie ma gwarancji, że rozmowa będzie na miejscu, ale masz większe szanse z lambdami. Jednym ze sposobów sprawdzenia, czy połączenie zostało zainicjowane, jest sprawdzenie wygenerowanego kodu. Jeśli używasz gcc, przekaż flagę -S do kompilatora. Oczywiście zakłada, że ​​można zrozumieć kod zespołu.

+21

Każdy może czytać kod zespołu, pytanie brzmi, czy możesz go zrozumieć. – Bolpat

+3

Anonimowe downvotes nikomu nie pomagają. Co jest nie tak z pytaniem? – Ali

17

Po pierwsze: cały projekt lambdas w C++ polega na tym, że nie mają narzutu w porównaniu do wywołań funkcji. Dotyczy to zwłaszcza tego, że można do nich nawiązać połączenia.

Ale tu jest zamieszanie pojęć: "inline" jest połączeniem funkcji, tj. Jest stwierdzeniem o tym, jak funkcja jest zdefiniowana jako, a nie jak jest wywoływana. Ale funkcje zdefiniowane w linii mogą korzystać z optymalizacji kompilatora, dzięki której wywołania do takich funkcji są wstawiane. To inne, ale bardzo powiązane pojęcia.

Teraz w przypadku lambdas rzeczywistą funkcją jest operator() zdefiniowana jako w linii w anonimowej klasie. Bezpośrednie połączenia z lambda to bezpośrednie połączenia z numerem operator() i dlatego można je wstawiać.

11

To zależy od poziomu optymalizacji nadanego kompilatorowi. Weźmy na przykład te dwie funkcje, które są semantycznie identyczne. Jednym z nich jest styl C++ 11, drugi styl C.

void foo1 (void) 
{ 
    int arr[100]; 
    std::generate(std::begin(arr), std::end(arr), [](){return std::rand()%100;}); 
} 

void foo2 (void) 
{ 
    int arr[100]; 
    for (int *i = arr; i < arr+100; i++) *i = std::rand()%100; 
} 

Kompilacja ta z gcc -O4 emituje kod, który jest bardzo podobny (nie identyczne, ale równoważny złożoności) dla tych dwóch funkcji.

Jednak lambda nie jest inline podczas kompilacji niezoptymalizowanej (i nie są to std :: begin i std :: end calls).

Mimo że kompilator może (i robi) świetną robotę przy optymalizacji kodu stylu nowoczesnego, gdy zostanie o to poproszony, prawdopodobnie lub prawdopodobnie będzie to kara za wydajność tego rodzaju kodu w niezoptymalizowanej wersji debugowania .

+9

Nie ma rzeczywistego "-O4" w gcc przy okazji. – DrYak

+8

@DrYak Zawsze kompiluję z "-O9999", ponieważ nie znalazłem [ogranicznika] (http://finalfantasy.wikia.com/wiki/Break_Damage_Limit) jeszcze ... Oczywiście, że jestem. Technicznie wszystko powyżej "-O3" oznacza "-O3". –

Powiązane problemy