2008-10-01 12 views

Odpowiedz

37

Funkcja jest umieszczony w kodzie, zamiast nazywa, podobnie jak przy użyciu makr (koncepcyjnie)

Może to zwiększyć prędkość (bez wywołania funkcji), ale powoduje, że kod uwędzić (jeśli funkcja jest używana 100 razy masz teraz 100 kopii)

należy pamiętać, to nie zmusić kompilator, aby funkcją inline, a będzie cię ignorują, jeśli uzna to za swój zły pomysł. Podobnie kompilator może zdecydować się na utworzenie dla Ciebie normalnych funkcji.

Umożliwia to również umieszczenie całej funkcji w pliku nagłówkowym, zamiast implementować ją w pliku cpp (co nie ma sensu, ponieważ wtedy otrzymasz nierozwiązany zewnętrzny, jeśli został zadeklarowany jako wbudowany, chyba że tylko to użył go plik cpp).

+1

Tak, i jest to kluczowy punkt jest, że współczesne kompilatory inline automatycznie i użycie słowa kluczowego "inline" to tylko sugestia dla kompilatora. Współcześni kompilatorzy na ogół wiedzą, co robią i poprawnie wybierają wbudowane lub nie, niezależnie od słów kluczowych "wbudowanych". Ale wciąż jest to przydatna koncepcja. – Jamie

+5

UWAGA: inline nie _nie oznacza, że ​​funkcja będzie inline. Można go znaleźć, to wciąż zależy od kompilatora. Jednak na poziomie języka/semantyki inline oznacza, że ​​funkcję można zdefiniować w więcej niż jednym module bez błędu czasu połączenia. (definicje muszą jednak pasować). – Aaron

+4

"Należy zauważyć, że to nie zmusza kompilatora do włączenia funkcji" –

2

Ciało funkcji wstawiana jest wewnątrz funkcji połączeń. Tak więc, jeśli masz wiele połączeń z tą funkcją, otrzymujesz wiele kopii kodu. Korzyścią jest szybsza realizacja.

zwykle bardzo krótki funkcja są wstawiane, gdy kopia ciele funkcji byłby niewiele większy niż zwykłego kodu prolog/epilogu wygenerowanego dla normalnego wywołania funkcji.

można przeczytać więcej w artykule MSDN o inline - http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx

0

Nieformalnie, oznacza to, że kompilatory wolno szczepić zawartość funkcji na miejscu połączenia, tak że nie ma wywołanie funkcji. Jeśli funkcja ma duże sprawozdań kontrolnych (np if, switch, itd.), A warunki mogą być oceniane w czasie kompilacji w miejscu połączenia (np stałych używanych w miejscu połączenia), a następnie kod kończy się znacznie mniejszy (nieużywane gałęzie są usuwane).

Bardziej formalnie, funkcje inline mają różne powiązania zbyt. Pozwolę ekspertom C++ mówić o tym aspekcie.

1

Funkcje śródliniowe zmieniają profil wydajności aplikacji poprzez ewentualne generowanie instrukcji umieszczanych w segmencie kodu aplikacji. To, czy funkcja jest inline, zależy od kompilatora. Z mojego doświadczenia wynika, że ​​większość współczesnych kompilatorów dobrze określa, kiedy zastosować się do żądania użytkownika.

W wielu przypadkach inline funkcję poprawi jego wydajność. Istnieje nieodłączny nacisk na wywołania funkcji. Istnieją jednak powody, dla których wstawianie funkcji może być ujemne:

  • Zwiększenie rozmiaru pliku binarnego przez powielenie kodu może spowodować dysk twardy, spowalniając działanie aplikacji.
  • Kod wprowadzający może przyczynić się do pomyłek w pamięci podręcznej lub może przyczynić się do trafień w pamięci podręcznej w zależności od architektury.

C++ FAQ robi dobrą robotę tłumacząc zawiłości kluczowe: http://www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.3

+0

Najczęściej zadawane pytania znajdują się teraz tutaj: https://isocpp.org/wiki/faq/inline-functions – GetFree

0

Wywołanie funkcji narzuca pewną karę wydajności dla procesora na tylko mające liniowy strumień instrukcji. Rejestry procesora muszą być zapisane w innej lokalizacji itp. Oczywiście korzyści wynikające z posiadania funkcji zwykle przewyższają karę wykonania.Ale tam, gdzie wydajność będzie problemem, na przykład legendarna funkcja "wewnętrznej pętli" lub inne wąskie gardło, kompilator może wstawić kod maszynowy dla funkcji do głównego strumienia wykonania, zamiast przechodzić przez podatek procesora w celu wywołania funkcji .

+1

Masz absolutną rację, składanie wewnętrznych pętli i pozbycie się odległych skoków powoduje zmniejszenie liczby utraconych cykli procesora z powodu chybienia pamięci podręcznej, przez co wzrasta wydajność z jednej strony, ale zwiększa ślad podręczny z drugiej strony. Dlatego ważne jest zrównoważenie tych kompromisów. – Josef

19

Podobnie jak inne (idealnie poprawne) odpowiedzi dotyczące wpływu wydajności inline, w C++, należy również pamiętać, to pozwala bezpiecznie umieścić funkcję w nagłówku:

// my_thing.h 
inline int do_my_thing(int a, int b) { return a + b; } 

// use_my_thing.cpp 
#include "my_thing.h" 
... 
    set_do_thing(&do_my_thing); 

// use_my_thing_again.cpp 
... 
    set_other_do_thing(&do_my_thing); 

To dlatego, że kompilator zawiera tylko rzeczywistą treść funkcji w pierwszym pliku obiektowym, który wymaga kompilacji funkcji regularnego wywoływania (zwykle dlatego, że adres został zrobiony, jak pokazano powyżej).

bez słowa kluczowego inline większość kompilatorów dałoby błąd o wielokrotnej definicji, np MSVC:

use_my_thing_again.obj : error LNK2005: "int __cdecl do_my_thing(int,int)" ([email protected]@[email protected]) already defined in use_my_thing.obj 
<...>\Scratch.exe : fatal error LNK1169: one or more multiply defined symbols found 
0

funkcję, która Ci Oznacz jako inline może być wstawiane przez kompilator. Nie ma gwarancji, że compielr to zrobi. Sam kompilator używa złożonej semantyki do urządzenia, kiedy to robi.

Gdy kompilator zdecyduje, że funkcja powinna być inline, wywołanie funkcji, w kodzie wywołującym jest zastąpione kodem calee. Oznacza to, że zapisujesz operacje na stosie, samo wywołanie i poprawiasz lokalizację pamięci podręcznej kodu. Czasami może to prowadzić do ogromnego wzrostu wydajności. Zwłaszcza w funkcjach dostępu do danych w jednym wierszu, takich jak akcesory używane w kodzie zorientowanym obiektowo.

Koszt jest zwykle taki, który spowoduje większy kod, co może zaszkodzić wydajności. Dlatego ustawienie funkcji inline jest tylko "zieloną flagą" dla kompilatora, której nie musi przestrzegać. Kompilator spróbuje zrobić to, co najlepsze.

Jako ogólna zasada dla początkujących, którzy nie chcą zajmować się osobliwościami powiązań. Funkcja inline ma być wywołana przez inną funkcję w tych samych jednostkach kompilacji. Jeśli chcesz zaimplementować funkcję inline, która może być używana w wielu jednostkach kompilacji, ustaw ją jako deklarację nagłówka i zaimplementuj funkcję inline.

Dlaczego?

przykład: w pliku nagłówka inlinetest.h

int foo(); 
inline int bar(); 

Na inlinetest.cpp jednostki kompilacji

int foo(){ int r = bar(); return r; } 


inline int bar(){ return 5;}; 

następnie w main.cpp

#include "inlinetest.h" 
int main() 
{ 
    foo(); 
//bar(); 
    } 

kompilacji pliku jeden obiekt na czas. Jeśli odkomentujesz to wywołanie "bar", wystąpi błąd. Ponieważ funkcja wstawiania jest zaimplementowana tylko w pliku obiektu inlinetest.o i nie jest eksportowana. W tym samym czasie funkcja foo najprawdopodobniej ma wbudowany kod funkcji paska (ponieważ słupek jest operacją I/O z pojedynczą linią, wtedy jest bardzo prawdopodobne, że jest inline)

Ale jeśli w pliku nagłówkowym miałeś zadeklarował funkcję inline i zaimplementował ją inline, a następnie mógłbyś jej użyć w dowolnej jednostce kompilacji, która zawiera ten nagłówek. ("próbka kodu");

Usunięcie wstawionego słowa kluczowego i kompilatora NIE spowoduje błędu nawet w przypadku wywołania barowego w głównym oknie i nie zostanie wykonane żadne wstawianie, chyba że użytkownik poprosi kompilator o wpisanie wszystkich funkcji.To nie jest standardowe zachowanie w większości kompilatorów.

20

Oznacza to tylko jedno i jedno: kompilator będzie wymazywał wiele definicji funkcji.

Funkcja zwykle nie może być zdefiniowana wiele razy (tj. Jeśli umieścisz nieliniową definicję funkcji w nagłówku, a następnie # umieścisz ją w wielu jednostkach kompilacji, otrzymasz błąd linkera). Oznaczenie definicji funkcji jako "wbudowane" pomija ten błąd (łącznik zapewnia prawidłowe działanie).

TO NIE WIĘC ONA WSZYSTKO!

Co najważniejsze, NIE oznacza to, że kompilator osadzi skompilowaną funkcję w każdej witrynie wywołania. To, czy tak się dzieje, zależy wyłącznie od kaprysów kompilatora, a zwykle modyfikator wstawiający niewiele lub wcale nie zmienia w umyśle kompilatora. Kompilator może - i robi - funkcje inline, które nie są oznaczone jako wbudowane i może wywoływać funkcje dla funkcji oznaczonych jako wbudowane.

Pomijanie wielu definicji jest rzeczą do zapamiętania.

+0

Kompilatory tylko wbudowane, nie oznaczone, jako funkcje wstawiane TYLKO, jeśli tego zażądasz. Słowo kluczowe Inline wpływa na to. Wiem, dużo pracowałem w kodzie GCC, który robi to, aby stworzyć specjalność kompilatora na uniwersytecie. – OldMan

+7

Pracowałem również nad GCC. W tym plakacie jest w zasadzie poprawna. Ten post powinien znajdować się na początku listy. –

+0

Poprawne tylko na efektach nto casuse. Inline nie generuje żadnych dodatkowych informacji, które może wykorzystać linker. Pliki obiektów Compiel 2 i sprawdź. Pozwala na wiele definicji exaclty, ponieważ symbole nie są eksportowane! Nie dlatego, że to jest jego cel! – OldMan

3

@OldMan

Kompilatory tylko Inline non oznaczone jako funkcje inline TYLKO jeśli poprosisz o to, aby to zrobić.

Tylko jeśli przez "żądanie" masz na myśli "włącz optymalizacje".

Poprawne tylko na efektach nto casuse.

Jest poprawny w obu.

Inline nie generuje żadnych dodatkowych informacji, których może użyć linker. Pliki obiektów Compiel 2 i sprawdź. Pozwala na wiele definicji exaclty, ponieważ symbole nie są eksportowane! Nie dlatego, że to jest jego cel!

Co masz na myśli, "symbole nie są eksportowane"? funkcje inline nie są statyczne. Ich imiona są widoczne; mają zewnętrzne powiązania. Aby zacytować ze standardu C++:

void h(); inline void h(); // zewnętrzny łącznik

inline void l(); void l(); // external linkage

Rzecz wielorakich definicji jest bardzo ważna. To obowiązkowe:

Funkcja inline określa się w każdej jednostce tłumaczeniowej, w której jest używany i ma dokładnie taką samą definicję w każdym przypadku (3.2). [Uwaga: można wywołać wywołanie funkcji inline zanim jego definicja pojawi się w jednostce tłumaczeniowej. ] Jeżeli funkcja z zewnętrznym powiązaniem jest zadeklarowana w jednej jednostce przeliczeniowej , powinna być zadeklarowana liniowo we wszystkich jednostkach tłumaczeniowych, w których się pojawia; diagnostyka nie jest wymagana.Funkcja liniowa z zewnętrznym łącznikiem musi mieć ten sam adres we wszystkich jednostkach tłumaczeniowych.