Na przykład mam następujący kod:
auto z = [](int x) -> int {
if (x > 0) {
switch (x) {
case 2: return 5;
case 3: return 6;
default: return 1;
}
}
return 0;
};
A potem dzwonię kilka razy. W kodzie asm widzę wywołania zewnętrzne z lambda .... coś ... To staje się trudne do odczytania i myślę, że może to również powodować wydajność. Więc może wygrywam w metaprogramowaniu, ale czy przegrywam w debugowaniu asm i wydajności? Czy powinienem unikać nowoczesnych funkcji językowych, makr i innych aspektów programowania, aby mieć pewność co do wydajności i prostoty debugowania?
if
to całkowicie zbędne w przykładowym kodzie i chociaż kompilator prawdopodobnie złapie, że nie ma powodu, aby kusić złą prognozę gałęzi.Odpowiedzi:
Nie , nie kiedy piszesz swój kod po raz pierwszy i nie odczuwasz żadnych realnych, mierzalnych problemów z wydajnością. W przypadku większości zadań jest to standardowy przypadek. Zbyt wczesne myślenie o optymalizacji nazywa się „przedwczesną optymalizacją”, i istnieją dobre powody, dla których D. Knuth nazwał to „źródłem wszelkiego zła” .
Tak , kiedy mierzysz prawdziwe, dające się udowodnić wąskie gardło wydajności i identyfikujesz ten konkretny konstrukt lambda jako główną przyczynę. W takim przypadku dobrym pomysłem może być zapamiętanie „prawa nieszczelnych abstrakcji” Joela Spolsky'ego i przemyślenie, co może się wydarzyć na poziomie asm. Ale uwaga, możesz być zaskoczony, jak niewielki będzie wzrost wydajności, gdy zamienisz konstruktor lambda na „niezbyt nowoczesny” konstrukt językowy (przynajmniej przy korzystaniu z porządnego kompilatora C ++).
źródło
Wybór pomiędzy lambda a klasą funktorów jest kompromisem.
Zysk z lambda jest w większości składniowy, ponieważ minimalizuje liczbę podstawek i pozwala na wpisanie kodu związanego z koncepcją wewnątrz funkcji, która będzie go używać (natychmiast lub później).
Pod względem wydajności nie jest to gorsze niż klasa funktorów , która jest strukturą C ++ lub klasą zawierającą pojedynczą „metodę”. W rzeczywistości kompilatory traktują lambda nie inaczej niż generowana przez kompilator klasa funktorów za sceną.
W twoim kodzie pod względem wydajności nie różni się niczym od wywołania funkcji, ponieważ ta klasa funktorów nie ma żadnego stanu (ponieważ ma pustą klauzulę przechwytywania), a zatem nie wymaga alokacji, konstruktora ani zniszczenia.
Debugowanie dowolnego nietrywialnego kodu C ++ za pomocą deasemblera zawsze było trudnym zadaniem. Jest to prawdą z użyciem lambda lub bez. Jest to spowodowane zaawansowaną optymalizacją kodu przez kompilator C ++, która spowodowała zmianę kolejności, przeplatanie i eliminację martwego kodu.
Aspekt zmieniający nazwy jest nieco niesmaczny, a obsługa debuggera dla lambda jest wciąż w powijakach . Można mieć tylko nadzieję, że z czasem poprawi się obsługa debuggera.
Obecnie najlepszym sposobem debugowania kodu lambda jest użycie debugera, który obsługuje ustawianie punktów przerwania na poziomie kodu źródłowego, tj. Poprzez podanie nazwy pliku źródłowego i numeru linii.
źródło
Aby dodać do odpowiedzi @DocBrown, pamiętaj, że obecnie procesory są tanie, ale praca jest droga.
W ogólnym koszcie programu sprzęt jest zwykle trywialny w porównaniu z kosztami utrzymania, które są zdecydowanie najdroższą częścią typowego projektu (nawet więcej niż jego rozwój).
Dlatego Twój kod musi optymalizować konserwację ponad wszystko inne, z wyjątkiem sytuacji, gdy wydajność ma krytyczne znaczenie (i nawet wtedy należy rozważyć konserwację).
źródło