C++ fornisce funzioni inline per ridurre il sovraccarico della chiamata di funzione. Una funzione inline è una funzione che viene espansa in linea quando viene chiamata. Quando viene chiamata la funzione inline, l'intero codice della funzione inline viene inserito o sostituito nel punto della chiamata della funzione inline. Questa sostituzione viene eseguita dal compilatore C++ in fase di compilazione. Una funzione in linea può aumentare l'efficienza se è piccola.
Sintassi:
inline return-type function-name(parameters) { // function code }>
Ricorda, l'inlining è solo una richiesta al compilatore, non un comando. Il compilatore può ignorare la richiesta di incorporamento.
Il compilatore potrebbe non eseguire l'inlining in circostanze quali:
- Se una funzione contiene un loop. ( per, mentre e fare-mentre )
- Se una funzione contiene variabili statiche.
- Se una funzione è ricorsiva.
- Se il tipo restituito da una funzione è diverso da void e l'istruzione return non esiste nel corpo della funzione.
- Se una funzione contiene un'istruzione switch o goto.
Perché vengono utilizzate le funzioni in linea?
Quando il programma esegue l'istruzione di chiamata della funzione, la CPU memorizza l'indirizzo di memoria dell'istruzione successiva alla chiamata della funzione, copia gli argomenti della funzione nello stack e infine trasferisce il controllo alla funzione specificata. La CPU quindi esegue il codice della funzione, memorizza il valore restituito dalla funzione in una posizione/registro di memoria predefinito e restituisce il controllo alla funzione chiamante. Ciò può diventare un sovraccarico se il tempo di esecuzione della funzione è inferiore al tempo di passaggio dalla funzione chiamante alla funzione chiamata (chiamato).
Per le funzioni di grandi dimensioni e/o che eseguono attività complesse, il sovraccarico della chiamata di funzione è in genere insignificante rispetto alla quantità di tempo necessaria per l'esecuzione della funzione. Tuttavia, per le funzioni piccole e di uso comune, il tempo necessario per effettuare la chiamata alla funzione è spesso molto superiore al tempo necessario per eseguire effettivamente il codice della funzione. Questo sovraccarico si verifica per le funzioni piccole perché il tempo di esecuzione di una funzione piccola è inferiore al tempo di commutazione.
Funzioni inline Vantaggi:
- Il sovraccarico della chiamata di funzione non si verifica.
- Inoltre, consente di risparmiare il sovraccarico delle variabili push/pop nello stack quando viene chiamata una funzione.
- Inoltre, consente di risparmiare il sovraccarico di una chiamata di ritorno da una funzione.
- Quando inlinei una funzione, puoi consentire al compilatore di eseguire un'ottimizzazione specifica del contesto sul corpo della funzione. Tali ottimizzazioni non sono possibili per le normali chiamate di funzione. Altre ottimizzazioni si possono ottenere considerando i flussi del contesto chiamante e del contesto chiamato.
- Una funzione inline può essere utile (se è piccola) per i sistemi embedded perché inline può produrre meno codice della funzione chiamata preambolo e ritorno.
Funzione in linea Svantaggi:
- Le variabili aggiunte dalla funzione inline consumano registri aggiuntivi. Dopo la funzione inline, se il numero della variabile che utilizzerà il registro aumenta, potrebbero creare un sovraccarico sull'utilizzo delle risorse della variabile del registro. Ciò significa che quando il corpo della funzione inline viene sostituito nel punto della chiamata della funzione, viene inserito anche il numero totale di variabili utilizzate dalla funzione. Pertanto aumenterà anche il numero di registri da utilizzare per le variabili. Pertanto, se i numeri delle variabili incorporati dopo la funzione aumentassero drasticamente, ciò causerebbe sicuramente un sovraccarico sull'utilizzo del registro.
- Se utilizzi troppe funzioni inline, la dimensione del file eseguibile binario sarà grande, a causa della duplicazione dello stesso codice.
- Un eccessivo incorporamento può anche ridurre il tasso di successo della cache delle istruzioni, riducendo così la velocità di recupero delle istruzioni da quella della memoria cache a quella della memoria primaria.
- La funzione inline può aumentare il tempo di compilazione se qualcuno modifica il codice all'interno della funzione inline, quindi tutta la posizione chiamante deve essere ricompilata perché al compilatore verrebbe richiesto di sostituire nuovamente tutto il codice per riflettere le modifiche, altrimenti continuerà con il vecchio funzionalità.
- Le funzioni in linea potrebbero non essere utili per molti sistemi embedded. Perché nei sistemi embedded la dimensione del codice è più importante della velocità.
- Le funzioni inline potrebbero causare problemi perché l'inlining potrebbe aumentare la dimensione del file eseguibile binario. Il thrashing della memoria provoca un peggioramento delle prestazioni del computer. Il seguente programma dimostra l'uso della funzione inline.
Esempio:
C++
#include> using> namespace> std;> inline> int> cube(>int> s) {>return> s * s * s; }> int> main()> {> >cout <<>'The cube of 3 is: '> << cube(3) <<>'
'>;> >return> 0;> }> |
>
>Produzione
The cube of 3 is: 27>
Funzioni e classi inline
È anche possibile definire la funzione inline all'interno della classe. Infatti tutte le funzioni definite all'interno della classe sono implicitamente inline. Pertanto anche qui vengono applicate tutte le limitazioni delle funzioni inline. Se devi dichiarare esplicitamente una funzione inline nella classe, dichiara semplicemente la funzione all'interno della classe e definila all'esterno della classe utilizzando la parola chiave inline.
Sintassi:
class S { public: inline int square(int s) // redundant use of inline { // this function is automatically inline // function body } };> Lo stile di cui sopra è considerato uno stile di programmazione errato. Il miglior stile di programmazione è semplicemente scrivere il prototipo della funzione all'interno della classe e specificarlo come inline nella definizione della funzione.
Per esempio:
class S { public: int square(int s); // declare the function }; inline int S::square(int s) // use inline prefix { }> Esempio:
C++
// C++ Program to demonstrate inline functions and classes> #include> using> namespace> std;> class> operation {> >int> a, b, add, sub, mul;> >float> div>;> public>:> >void> get();> >void> sum();> >void> difference();> >void> product();> >void> division();> };> inline> void> operation ::get()> {> >cout <<>'Enter first value:'>;> >cin>>a;> >cout <<>'Enter second value:'>;> >cin>>b;> }> inline> void> operation ::sum()> {> >add = a + b;> >cout <<>'Addition of two numbers: '> << a + b <<>'
'>;> }> inline> void> operation ::difference()> {> >sub = a - b;> >cout <<>'Difference of two numbers: '> << a - b <<>'
'>;> }> inline> void> operation ::product()> {> >mul = a * b;> >cout <<>'Product of two numbers: '> << a * b <<>'
'>;> }> inline> void> operation ::division()> {> >div> = a / b;> >cout <<>'Division of two numbers: '> << a / b <<>'
'>;> }> int> main()> {> >cout <<>'Program using inline function
'>;> >operation s;> >s.get();> >s.sum();> >s.difference();> >s.product();> >s.division();> >return> 0;> }> |
>
sincronizzazione dei thread
>
Produzione:
Enter first value: 45 Enter second value: 15 Addition of two numbers: 60 Difference of two numbers: 30 Product of two numbers: 675 Division of two numbers: 3>
Cosa c'è che non va nella macro?
I lettori che hanno familiarità con il linguaggio C sanno che il linguaggio C utilizza le macro. Il preprocessore sostituisce tutte le chiamate macro direttamente all'interno del codice macro. Si consiglia di utilizzare sempre la funzione inline anziché la macro. Secondo il Dr. Bjarne Stroustrup, il creatore del C++ le macro non sono quasi mai necessarie in C++ e sono soggette a errori. Ci sono alcuni problemi con l'uso delle macro in C++. La macro non può accedere ai membri privati della classe. Le macro sembrano chiamate di funzioni ma in realtà non lo sono.
Esempio:
C++
// C++ Program to demonstrate working of macro> #include> using> namespace> std;> class> S {> >int> m;> public>:> >// error> #define MAC(S::m)> };> |
>
>
Produzione:
Error: '::' may not appear in macro parameter list #define MAC(S::m)>
Il compilatore C++ controlla i tipi di argomento delle funzioni inline e le conversioni necessarie vengono eseguite correttamente. La macro del preprocessore non è in grado di eseguire questa operazione. Un'altra cosa è che le macro sono gestite dal preprocessore e le funzioni inline sono gestite dal compilatore C++. Ricorda: è vero che tutte le funzioni definite all'interno della classe sono implicitamente inline e il compilatore C++ eseguirà chiamate inline di queste funzioni, ma il compilatore C++ non può eseguire inline se la funzione è virtuale. Il motivo per cui viene chiamata una funzione virtuale viene risolto in fase di esecuzione anziché in fase di compilazione. Virtuale significa attendere fino al runtime e inline significa durante la compilazione, se il compilatore non sa quale funzione verrà chiamata, come può eseguire l'inlining? Un'altra cosa da ricordare è che è utile rendere la funzione in linea solo se il tempo impiegato durante una chiamata di funzione è maggiore rispetto al tempo di esecuzione del corpo della funzione.
Un esempio in cui la funzione inline non ha alcun effetto:
inline void show() { cout << 'value of S = ' << S << endl; }> La funzione di cui sopra richiede relativamente molto tempo per essere eseguita. In generale, una funzione che esegue un'operazione di input-output (I/O) non dovrebbe essere definita come inline perché impiega una notevole quantità di tempo. Tecnicamente l'incorporamento della funzione show() ha un valore limitato perché la quantità di tempo impiegata dall'istruzione I/O supera di gran lunga il sovraccarico di una chiamata di funzione. A seconda del compilatore che stai utilizzando, il compilatore potrebbe mostrare un avviso se la funzione non viene espansa in linea.
Linguaggi di programmazione come Java e C# non supportano le funzioni inline. Ma in Java, il compilatore può eseguire l'inlining quando viene chiamato il piccolo metodo finale perché i metodi finali non possono essere sovrascritti dalle sottoclassi e la chiamata a un metodo finale viene risolta in fase di compilazione.
In C# il compilatore JIT può anche ottimizzare il codice incorporando piccole chiamate di funzione (come sostituire il corpo di una piccola funzione quando viene chiamata in un ciclo). L'ultima cosa da tenere a mente è che le funzioni inline sono una caratteristica preziosa del C++. L’uso appropriato delle funzioni inline può fornire un miglioramento delle prestazioni, ma se le funzioni inline vengono utilizzate arbitrariamente, non possono fornire risultati migliori. In altre parole, non aspettarti una prestazione migliore del programma. Non rendere tutte le funzioni in linea. È meglio mantenere le funzioni inline il più piccole possibile.