Cosa significa per una funzione C ++ essere in linea?

Vedi titolo: cosa significa per una funzione C ++ essere in linea?

La funzione viene inserita nel codice, anziché essere chiamata, in modo simile all’utilizzo di macro (concettualmente)

Questo può migliorare la velocità (nessuna chiamata di funzione), ma causa un aumento di codice (se la funzione viene utilizzata 100 volte, ora ne hai 100)

Dovresti notare che questo non costringe il compilatore a rendere la funzione in linea, e ti ignorerà se pensa che sia una ctriggers idea. Allo stesso modo il compilatore può decidere di rendere normali le funzioni in linea per te.

Ciò consente anche di posizionare l’intera funzione in un file di intestazione, anziché implementarla in un file cpp (che comunque non è ansible, da allora si ottiene un esterno non risolto se è stato dichiarato in linea, a meno che, naturalmente, solo quel file cpp lo abbia usato ).

Significa una cosa e una sola cosa: che il compilatore eliderà più definizioni della funzione.

Una funzione normalmente non può essere definita più volte (cioè se si posiziona una definizione di funzione non in linea in un’intestazione e quindi si include # in più unità di compilazione, si riceverà un errore del linker). Contrassegnare la definizione della funzione come “in linea” sopprime questo errore (il linker assicura che la cosa giusta si verifichi).

NON SIGNIFICA ALTRO ANCORA!

Soprattutto, NON significa che il compilatore incorporerà la funzione compilata in ogni sito di chiamata. Che ciò avvenga dipende interamente dai capricci del compilatore, e in genere il modificatore in linea fa poco o nulla per cambiare la mente del compilatore. Il compilatore può – e lo fa – funzioni inline che non sono contrassegnate in linea e possono effettuare chiamate di funzione a funzioni che sono contrassegnate in linea.

Elidere più definizioni è la cosa da ricordare.

Così come le altre (perfettamente corrette) risposte circa le implicazioni sulle prestazioni di inline , in C ++ dovresti anche notare che questo ti permette di mettere in sicurezza una funzione in un’intestazione:

 // 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); 

Questo perché il compilatore include solo il corpo reale della funzione nel primo file object che necessita di una normale funzione callable da compilare (normalmente perché è stato preso l’indirizzo, come ho mostrato sopra).

Senza la parola chiave inline , la maggior parte dei compilatori darebbe un errore sulla definizione multipla, ad es. Per 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 

@Vecchio uomo

I compilatori solo non sono contrassegnati come funzioni inline SOLO se lo si richiede di farlo.

Solo se per “richiesta” si intende “triggersre le ottimizzazioni”.

È corretto solo sugli effetti nel casus.

È corretto in entrambi.

In linea non genera alcuna informazione aggiuntiva che il linker può utilizzare. Compiel 2 file object e verifica. Permette un’esistente definizione multipla perché i simboli non vengono esportati! Non perché questo è il suo objective!

Cosa intendi con “i simboli non vengono esportati”? le funzioni inline non sono statiche. I loro nomi sono visibili; hanno un collegamento esterno. Per citare lo standard C ++:

void h (); inline void h (); // collegamento esterno

inline void l (); void l (); // collegamento esterno

La cosa delle definizioni multiple è molto l’objective. È obbligatorio:

Una funzione inline deve essere definita in ogni unità di traduzione in cui viene utilizzata e deve avere esattamente la stessa definizione in ogni caso (3.2). [Nota: è ansible incontrare una chiamata alla funzione inline prima che la sua definizione venga visualizzata nell’unità di traduzione. ] Se una funzione con collegamento esterno è dichiarata in linea in una unità di traduzione, deve essere dichiarata in linea in tutte le unità di traduzione in cui appare; non è richiesta alcuna diagnosi Una funzione inline con collegamento esterno deve avere lo stesso indirizzo in tutte le unità di traduzione.

Il corpo della funzione è letteralmente inserito all’interno della funzione chiamante. Pertanto, se si dispone di più chiamate a questa funzione, si ottengono più copie del codice. Il vantaggio è che ottieni un’esecuzione più veloce.

Di solito le funzioni molto brevi sono in linea, quando la copia del corpo della funzione non è molto più grande del solito codice prologo / epilogo generato per la normale chiamata di funzione.

Puoi leggere di più sull’articolo di MSDN su inline – http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx

Le funzioni in linea alterano il profilo delle prestazioni della tua applicazione, probabilmente generando istruzioni che vengono inserite nel segmento di codice della tua applicazione. Se una funzione è in linea è a discrezione del compilatore. Nella mia esperienza, i compilatori più moderni sono bravi a determinare quando conformarsi alla richiesta di un utente in linea.

In molti casi, l’integrazione di una funzione migliorerà le sue prestazioni. C’è un sovraccarico inerente per funzionare le chiamate. Ci sono dei motivi, tuttavia, perché la definizione di una funzione potrebbe essere negativa:

  • Aumentare la dimensione dell’eseguibile binario duplicando il codice potrebbe portare al disco thrashing, rallentando l’applicazione.
  • Il codice di allineamento potrebbe contribuire alla mancata memorizzazione della cache, o eventualmente contribuire alla cache di hit a seconda della tua architettura.

Le domande frequenti su C ++ fanno un buon lavoro nello spiegare le complessità della parola chiave: http://www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.3

Informalmente, significa che i compilatori sono autorizzati ad inserire il contenuto della funzione nel sito di chiamata, in modo che non vi sia alcuna chiamata di funzione. Se la tua funzione ha grandi istruzioni di controllo (ad esempio, if , switch , ecc.) E le condizioni possono essere valutate in fase di compilazione nel sito di chiamata (ad esempio, i valori costanti utilizzati nel sito di chiamata), il tuo codice finisce molto più piccolo ( i rami non utilizzati vengono lasciati fuori).

Più formalmente, le funzioni in linea hanno anche un collegamento diverso. Lascerò che gli esperti di C ++ parlino di questo aspetto.

Chiamare una funzione impone una certa penalizzazione delle prestazioni per la CPU semplicemente avendo un stream lineare di istruzioni. I registri della CPU devono essere scritti in un’altra posizione, ecc. Ovviamente i vantaggi di avere funzioni di solito superano la penalità delle prestazioni. Ma, dove le prestazioni saranno un problema, ad esempio la favolosa funzione “loop interno” o qualche altro collo di bottiglia, il compilatore può inserire il codice macchina per la funzione nel stream principale di esecuzione invece di passare attraverso la tassa della CPU per chiamare una funzione .

È ansible che una funzione contrassegnata come inline sia delineata dal compilatore. Non vi è alcuna garanzia che compielr lo farà. Il compilatore stesso utilizza semantica complessa sul dispositivo quando farlo o meno.

Quando il compilatore decide che una funzione deve essere sottolineata, la chiamata alla funzione, nel codice del chiamante viene sostituita dal codice del calee. Ciò significa che risparmi le operazioni di stack, la chiamata stessa e migliora la localizzazione della cache del codice. A volte ciò può comportare enormi guadagni in termini di prestazioni. Specialmente nelle funzioni di accesso ai dati a 1 riga, come le accessorie utilizzate nel codice Object Oriented.

Il costo è che di solito questo si tradurrà in un codice più grande, cosa che potrebbe danneggiare le prestazioni. Ecco perché l’impostazione di una funzione in linea è solo una “bandiera verde” per il compilatore, che non ha bisogno di seguire. Il compilatore proverà a fare ciò che è meglio.

Come regola empirica per i principianti che non vogliono affrontare le peculiarità del linkage. la funzione inline deve essere chiamata da un’altra funzione nelle stesse unità di compilazione. Se si desidera implementare una funzione inline che può essere utilizzata su più unità di compilazione, renderla un file di intestazione dichiarato e implementato in linea.

Perché?

Esempio: nel file di intestazione inlinetest.h

 int foo(); inline int bar(); 

Nell’unità di compilazione inlinetest.cpp

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

Quindi al main.cpp

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

Compilare un file object alla volta. Se disapprovi quella chiamata “bar” avresti un errore. Poiché la funzione inline è implementata solo nel file object inlinetest.o e non viene esportata. Allo stesso tempo la funzione foo, molto probabilmente ha incorporato su di essa il codice della funzione bar (dato che la barra è a riga singola senza operazioni di I / O quindi è molto probabile che sia in linea)

Ma se nel file di intestazione era stata dichiarata la funzione inline e implementata in linea, sarebbe ansible utilizzarla in qualsiasi unità di compilazione che includesse quell’intestazione. (“codice di esempio”);

Rimuove la parola chiave inline e il compilatore NON causerà l’errore anche con la chiamata della sbarra al main E non verrà eseguito alcun inline a meno che non chieda al compilatore di incorporare tutte le funzioni. Questo non è un comportamento standard sulla maggior parte dei compilatori.