Wiem, że inline jest wskazówką lub żądaniem kompilatora i służy do unikania narzutów wywołania funkcji.
Na jakiej podstawie można ustalić, czy funkcja jest kandydatem do inklinacji, czy nie? W którym przypadku należy unikać wkładania?
Wiem, że inline jest wskazówką lub żądaniem kompilatora i służy do unikania narzutów wywołania funkcji.
Na jakiej podstawie można ustalić, czy funkcja jest kandydatem do inklinacji, czy nie? W którym przypadku należy unikać wkładania?
Odpowiedzi:
Uniknięcie kosztów wywołania funkcji to tylko połowa sukcesu.
robić:
inline
zamiast#define
inline
: szybszy kod i mniejsze pliki wykonywalne (większe szanse na pozostanie w pamięci podręcznej kodu)nie:
opracowując bibliotekę, aby uczynić klasę rozszerzalną w przyszłości, powinieneś:
Pamiętaj, że inline
słowo kluczowe jest wskazówką dla kompilatora: kompilator może zdecydować, że nie wstawi funkcji, i może zdecydować o wstawieniu funkcji, które nie zostały oznaczone inline
w pierwszej kolejności. Generalnie unikam funkcji znakowaniainline
(może poza pisaniem bardzo małych funkcji).
Jeśli chodzi o wydajność, rozsądnym podejściem jest (jak zawsze) profilowanie aplikacji, a następnie inline
zestaw funkcji reprezentujących wąskie gardło.
Bibliografia:
EDYCJA: Bjarne Stroustrup, język programowania C ++:
Można zdefiniować funkcję
inline
. Na przykład:
inline int fac(int n)
{
return (n < 2) ? 1 : n * fac(n-1);
}
Specyfikator
inline
jest wskazówką dla kompilatora, że powinien on próbować wygenerować kod dla wywołaniafac()
inline, a nie ustanowić kod dla funkcji raz, a następnie wywołać za pomocą zwykłego mechanizmu wywoływania funkcji. Sprytny kompilator może wygenerować stałą720
dla połączeniafac(6)
. Możliwość wzajemnie rekurencyjnych funkcji inline, funkcji inline, które powtarzają się lub nie zależą od danych wejściowych itp., Uniemożliwia zagwarantowanie, że każde wywołanieinline
funkcji jest wstawiane. Stopień sprytności kompilatora nie może być regulowany, więc jeden kompilator może wygenerować720
, inny6 * fac(5)
, a jeszcze inny niewymagane wywołaniefac(6)
.Aby inlinizacja była możliwa przy braku niezwykle sprytnych narzędzi do kompilacji i łączenia, należy uwzględnić definicję - a nie tylko deklarację - funkcji wbudowanej (§9.2).
inline
Especifier nie wpływa semantyki funkcji. W szczególności funkcja wbudowana nadal ma unikalny adres, podobnie jakstatic
zmienne (§7.1.2) funkcji wbudowanej.
EDIT2: ISO-IEC 14882-1998, 7.1.2 Specyfikatory funkcji
Deklaracja funkcji (8.3.5, 9.3, 11.4) ze
inline
specyfikatorem deklaruje funkcję wbudowaną. Specyfikator wbudowany wskazuje implementacji, że podstawienie wbudowane funkcji w punkcie wywołania powinno być preferowane zamiast zwykłego mechanizmu wywoływania funkcji. Implementacja nie jest wymagana do wykonania tego wbudowanego podstawienia w punkcie wywołania; jednak nawet jeśli to wbudowane podstawienie zostanie pominięte, pozostałe zasady dla funkcji wbudowanych określone w 7.1.2 powinny być nadal przestrzegane.
inline
jest czymś więcej niż wskazówką dla kompilatora. Zmienia reguły językowe dotyczące wielu definicji. Ponadto posiadanie danych statycznych nie jest żeliwnym powodem, aby unikać wstawiania funkcji. Implementacja jest zobowiązana do przydzielenia pojedynczego obiektu statycznego dla każdej funkcji statycznej, niezależnie od tego, czy funkcja jest zadeklarowana, inline
czy nie. Klasy są nadal rozszerzalne, jeśli mają wbudowane konstruktory i wirtualne destruktory. A pusty nawias klamrowy to jedna wirtualna funkcja, którą czasem warto pozostawić w linii.
inline
, wynik jest taki, że funkcja nie jest wstawiana: płacisz cenę za wywołanie, a także każda jednostka tłumacząca, która zawiera i wywołuje funkcję, otrzymuje własną kopię kodu i zmiennych statycznych. Przyczyną niestawiania konstruktorów i destruktorów podczas tworzenia biblioteki jest binarna kompatybilność z przyszłymi wersjami twojej biblioteki
inline
niefunkcje można wstawiać, jeśli kompilator ma na to ochotę. I inline
funkcje nie będą inlined jeśli kompilator nie decyduje się je na rolkach. Jak powiedział Charles Bailey, zmienia reguły językowe. Zamiast myśleć o nim jako o wskazówce optymalizacyjnej, bardziej trafne jest myślenie o nim jako o zupełnie innej koncepcji. inline
Kluczowe informuje kompilator, aby umożliwić wiele definicji i nic innego. Optymalizację „wstawiania” można zastosować do prawie każdej funkcji, niezależnie od tego, czy jest zaznaczona inline
.
inline
, aby uzyskać wbudowane funkcje. Czasami chcemy innych korzyści, takich jak obejście ODR.
inline
ma bardzo mało wspólnego z optymalizacją. inline
jest instrukcją dla kompilatora, aby nie generować błędu, jeśli dana funkcja występuje wielokrotnie w programie, i obietnica, że definicja pojawi się w każdym używanym tłumaczeniu i wszędzie tam, gdzie się pojawi, będzie miała dokładnie tę samą definicję.
Biorąc pod uwagę powyższe zasady, inline
nadaje się do krótkich funkcji, których ciało nie musi zawierać dodatkowych zależności od tego, czego potrzebowałaby tylko deklaracja. Za każdym razem, gdy napotyka się definicję, należy ją przeanalizować, a kod dla jej treści może zostać wygenerowany, co oznacza narzut kompilatora na funkcję zdefiniowaną tylko raz w jednym pliku źródłowym.
Kompilator może inline (tj zastąpić wywołanie funkcji z kodu, który wykonuje, że działanie tej funkcji) każde wywołanie funkcji, które wybiera. Kiedyś było tak, że „oczywiście” nie można było wstawić funkcji, która nie została zadeklarowana w tej samej jednostce tłumaczenia co wywołanie, ale przy rosnącym wykorzystaniu optymalizacji czasu łącza nawet teraz nie jest to prawdą. Równie prawdą jest fakt, że zaznaczone funkcje inline
nie mogą być wstawiane.
inline
słowem kluczowym? A jaki jest szczęśliwy zbieg okoliczności?
Mówienie kompilatorowi, aby wstawił funkcję, jest optymalizacją, a najważniejszą zasadą optymalizacji jest to, że przedwczesna optymalizacja jest źródłem wszelkiego zła. Zawsze pisz czysty kod (używając wydajnych algorytmów), następnie profiluj swój program i optymalizuj tylko funkcje, które trwają zbyt długo.
Jeśli okaże się, że dana funkcja jest bardzo krótka i prosta, a wywoływana jest dziesiątki tysięcy razy w ciasnej pętli wewnętrznej, może być dobrym kandydatem.
Możesz być zaskoczony - wiele kompilatorów C ++ automatycznie wstawi za ciebie małe funkcje - i mogą zignorować twoją prośbę o wstawienie.
/FAcs
w Visual Studio, -s
w GCC), aby zobaczyć dokładnie, co robi. Z mojego doświadczenia wynika, że oba te kompilatory dość mocno ważą wbudowane słowo kluczowe.
inline
słowa kluczowego g ++, ani VC nie ważą . Oznacza to, że jeśli zobaczysz funkcję wstawioną i usuniesz inline
z niej specyfikator, nadal będzie ona wstawiana. Jeśli masz jakieś konkretne przykłady przeciwne, udostępnij je!
inline
słowo kluczowe utrudnia „wyczyszczenie kodu”? Słowo kluczowe w „przedwczesnej optymalizacji” jest przedwczesne , a nie optymalizacja. Mówienie, że powinieneś aktywnie * unikać optymalizacji, to po prostu śmiecie. Chodzi o to, że powinieneś unikać optymalizacji, które mogą nie być konieczne, i mieć szkodliwe skutki uboczne dla kodu (takie jak zmniejszenie jego konserwacji). Nie widzę, w jaki sposób inline
słowo kluczowe sprawi, że kod będzie mniej konserwowalny, ani w jaki sposób dodanie go do funkcji może być szkodliwe.
Najlepszym sposobem, aby się tego dowiedzieć, jest profilowanie programu i oznaczanie małych funkcji, które są wywoływane wiele razy i przechodzą przez cykle procesora tak jak inline
. Słowo kluczowe jest tutaj „małe” - gdy narzut wywołania funkcji jest nieznaczny w porównaniu do czasu spędzonego w funkcji, nie ma sensu wstawiać ich.
Innym zastosowaniem, które zasugerowałem, jest to, że jeśli masz małe funkcje, które są wywoływane w kodzie krytycznym pod względem wydajności wystarczająco często, aby sprawić, że pamięć podręczna nie trafi, prawdopodobnie powinieneś je również wpisać. Znów jest to coś, co profiler powinien móc ci powiedzieć.
Przedwczesna optymalizacja jest źródłem wszelkiego zła!
Zazwyczaj umieszczam tylko „getters” i „setters”. Gdy kod działa i jest stabilny, profilowanie może pokazać, które funkcje mogą skorzystać z wstawiania.
Z drugiej strony, większość współczesnych kompilatorów ma całkiem dobre algorytmy optymalizacyjne i określi to, co powinieneś dla siebie napisać.
Reasuming - pisz wbudowane funkcje jednowierszowe, a później martw się o inne.
Funkcje wbudowane mogą wbudowane poprawić wydajność kodu, eliminując potrzebę wypychania argumentów do stosu. jeśli dana funkcja znajduje się w kluczowej części kodu, powinieneś podjąć decyzję inline inline w części dotyczącej optymalizacji projektu,
możesz przeczytać więcej o wstawieniach w często zadawanych pytaniach o c ++
Często używam funkcji wbudowanych nie jako optymalizacji, ale aby uczynić kod bardziej czytelnym. Czasami sam kod jest krótszy i łatwiejszy do zrozumienia niż komentarze, nazwy opisowe itp. Na przykład:
void IncreaseCount() { freeInstancesCnt++; }
Czytelnik natychmiast zna pełną semantykę kodu.
Generalnie stosuję zasadę kciuka, w której wykonuję funkcję z 3-4 prostymi instrukcjami jako wstawionymi. Warto jednak pamiętać, że jest to tylko wskazówka dla kompilatora. Ostatnie wywołanie, aby ustawić je jako wbudowane lub nie, jest podejmowane tylko przez kompilator. Jeśli jest ich więcej niż tyle, nie będę deklarować w wierszu, ponieważ w przypadku głupiego kompilatora może to prowadzić do wzdęcia kodu.
Decydując się na użycie w trybie inline, zwykle pamiętam o następującym pomyśle: Opóźnienie pamięci na nowoczesnych maszynach może być większym wąskim gardłem niż surowe obliczenia. Często wywoływane funkcje wstawiania zwiększają rozmiar pliku wykonywalnego. Ponadto taka funkcja może być przechowywana w pamięci podręcznej kodu procesora, co zmniejsza liczbę braków pamięci podręcznej, gdy potrzebny jest dostęp do tego kodu.
Dlatego musisz sam zdecydować: czy wstawianie zwiększa lub zmniejsza rozmiar generowanego kodu maszynowego? Jak prawdopodobne jest, że wywołanie funkcji spowoduje brak pamięci podręcznej? Jeśli jest on przeszyty całym kodem, powiedziałbym, że prawdopodobieństwo jest wysokie. Jeśli jest ograniczony do jednej ciasnej pętli, prawdopodobieństwo jest niskie.
Zazwyczaj używam inlinizacji w przypadkach, które wymienię poniżej. Jednak jeśli naprawdę zależy Ci na wydajności, profilowanie jest niezbędne. Ponadto możesz sprawdzić, czy kompilator rzeczywiście bierze podpowiedź.
Również metoda wbudowana ma poważne skutki uboczne przy utrzymywaniu dużych projektów. Po zmianie kodu wbudowanego wszystkie pliki, które go używają, zostaną automatycznie odbudowane przez kompilator (jest to dobry kompilator). Może to zmarnować dużo czasu na rozwój.
Kiedy inline
metoda jest przenoszona do pliku źródłowego i nie jest już wstawiana, cały projekt musi zostać przebudowany (przynajmniej takie było moje doświadczenie). A także, gdy metody są konwertowane na wbudowane.
inline
czy nie, nie ma znaczenia (poza tym bez inline
słowa kluczowego inline
Kiedy uważasz, że Twój kod jest wystarczająco mały, aby go używać jako wbudowanego i pamiętasz, że funkcja wbudowana powiela kod i wkleja go, gdy funkcja jest wywoływana, więc może być wystarczająco dobry, aby wydłużyć czas wykonywania, ale również zwiększyć zużycie pamięci. Nie możesz używać funkcji inline, gdy używasz pętli / zmiennej statycznej / rekurencyjnej / switch / goto / funkcji wirtualnej. Wirtualne oznacza poczekanie, aż środowisko wykonawcze i wbudowane oznaczają podczas kompilacji, więc nie można ich używać jednocześnie.
Przeczytałem kilka odpowiedzi i widzę, że czegoś brakuje.
Zasadą, której używam, nie jest używanie wbudowane, chyba że chcę, aby było wbudowane. Wygląda głupio, teraz wyjaśnienie.
Kompilatory są wystarczająco inteligentne, a krótkie funkcje są zawsze dostępne. I nigdy nie tworzy długiej funkcji jako wbudowanej, chyba że programista tak mówi.
Wiem, że inline jest wskazówką lub prośbą do kompilatora
W rzeczywistości inline
jest to zamówienie na kompilator, nie ma możliwości wyboru, a po inline
słowach kluczowych cały kod jest wstawiany. Dlatego nigdy nie możesz użyć inline
słowa kluczowego, a kompilator zaprojektuje najkrótszy kod.
Więc kiedy używać inline
?
Do użycia, jeśli chcesz mieć wbudowany kod. Znam tylko jeden przykład, ponieważ używam go tylko w jednej sytuacji. To jest uwierzytelnianie użytkownika.
Na przykład mam tę funkcję:
inline bool ValidUser(const std::string& username, const std::string& password)
{
//here it is quite long function
}
Bez względu na to, jak duża jest ta funkcja, chcę mieć ją wbudowaną, ponieważ utrudnia to złamanie mojego oprogramowania.
inline
jest dla początkującego C ++, coCFLAGS
jest dla początkującego w Gentoo: nie, kompilacja-O3 -funroll-loops -finline-functions
nie sprawi, że twój stary Pentium poleci;)