Funzioni inline
Le funzioni consentono di scomporre in piu` parti un grosso programma facilitandone
sia la realizzazione che la successiva manutenzione. Tuttavia spesso si e` indotti
a rinunciare a tale beneficio perche` l'overhead imposto dalla chiamata di una
funzione e` tale da sconsigliare la realizzazione di piccole funzioni. Le possibili
soluzioni in C erano due:
- Rinunciare alle funzioni piccole, tendendo a scrivere solo poche funzioni
corpose;
- Ricorrere alle macro;
La prima in realta` e` una pseudo-soluzione e porta spesso a programmi difficili
da capire e mantenere perche` in pratica rinuncia ai benefici delle funzioni;
la seconda soluzione invece potrebbe andare bene in C, ma non in C++: una macro
puo` essere vista come una funzione il cui corpo e` sostituito (espanso) dal
preprocessore in luogo di ogni chiamata. Il problema principale e` che questo
sistema rende difficoltoso ogni controllo statico di tipo poiche` gli errori
divengono evidenti solo quando la macro viene espansa; in C tutto sommato cio`
non costituisce un grave problema perche` il C non e` fortemente tipizzato.
Al contrario il C++ possiede un rigido sistema di tipi e l'uso di macro costituisce
un grave ostacolo allo sfruttamento di tale caratteristica. Esistono poi altri
svantaggi nell'uso delle macro: rendono difficile il debugging e non sono flessibili
come le funzioni (e` ad esempio difficile rendere fattibili macro ricorsive).
Per non rinunciare ai vantaggi forniti dalle (piccole) funzioni e a quelli
forniti da un controllo statico dei tipi, sono state introdotte nel C++ le funzioni
inline.
Quando una funzione viene definita inline il compilatore ne memorizza
il corpo e, quando incontra una chiamata a tale funzione, semplicemente lo sostituisce
alla chiamata della funzione; tutto cio` consente di evitare l'overhead della
chiamata e, dato che la cosa e` gestita dal compilatore, permette di eseguire
tutti i controlli statici di tipo.
Se si desidera che una funzione sia espansa inline dal compilatore, occorre
definirla esplicitamente inline :
inline int Sum(int a, int b) {
return a + b;
}
La keyword inline informa il compilatore che si desidera che la
funzione Sum sia espansa inline ad ogni chiamata; tuttavia cio`
non vuol dire che la cosa sia sempre possibile: molti compilatori non sono in
grado di espandere inline qualsiasi funzione, tipicamente le funzioni ricorsive
sono molto difficili da trattare e il mio compilatore non riesce ad esempio
a espandere funzioni contenenti cicli. In questi casi comunque la cosa generalmente
non e` grave, poiche` un ciclo tipicamente richiede una quantita` di tempo ben
maggiore di quello necessario a chiamare la funzione, per cui l'espansione inline
non avrebbe portato grossi benefici. Quando l'espansione inline della funzione
non e` possibile solitamente si viene avvisati da una warning.
Si osservi che, per come sono trattate le funzioni inline, non ha senso utilizzare
la keyword inline in un prototipo di funzione perche` il compilatore
necessita del codice contenuto nel corpo della funzione:
inline int Sum(int a, int b);
int Sum(int a, int b) {
return a + b;
}
In questo caso non viene generato alcun errore, ma la parola chiave inline
specificata nel prototipo viene del tutto ignorata; perche` abbia effetto inline
deve essere specificata nella definizione della funzione:
int Sum(int a, int b);
inline int Sum(int a, int b) {
return a + b;
} //
Ora e` tutto ok!
Un'altra cosa da tener presente e` che il codice che costituisce una funzione
inline deve essere disponibile prima di ogni uso della funzione, altrimenti
il compilatore non e` in grado di espanderla (non sempre almeno!). Una funzione
ordinaria puo` essere usata anche prima della sua definizione, poiche` e` il
linker che si occupa di risolvere i riferimenti (il linker del C++ lavora in
due passate); nel caso delle funzioni inline, poiche` il lavoro e` svolto dal
compilatore (che lavora in una passata), non e` possibile risolvere correttamente
il riferimento. Una importante conseguenza di tale limitazione e` che una funzione
puo` essere inline solo nell'ambito del file in cui e` definita, se un file
riferisce ad una funzione definita inline in un altro file (come, lo vedremo
piu` avanti), in questo file (il primo) la funzione non potra` essere espansa;
esistono comunque delle soluzioni al problema.
Le funzioni inline consentono quindi di conservare i benefici delle funzioni
anche in quei casi in cui le prestazioni sono fondamentali, bisogna pero` valutare
attentamente la necessita` di rendere inline una funzione, un abuso potrebbe
portare a programmi difficili da compilare (perche` e` necessaria molta memoria)
e voluminosi in termini di dimensioni del file eseguibile.
|