Domanda

Anche se in alcune situazioni sarebbe molto comodo utilizzare le funzioni inline,

Ci sono degli svantaggi con le funzioni inline?

Conclusione:

Apparentemente non c'è niente di sbagliato nell'usare le funzioni inline.

Ma vale la pena notare i seguenti punti!

  • L'uso eccessivo dell'inlining può effettivamente rallentare i programmi.A seconda della dimensione di una funzione, l'inlining può causare un aumento o una diminuzione della dimensione del codice.L'incorporamento di una funzione di accesso molto piccola in genere riduce la dimensione del codice, mentre l'incorporamento di una funzione molto grande può aumentare notevolmente la dimensione del codice.Sui processori moderni il codice più piccolo di solito viene eseguito più velocemente grazie a un migliore utilizzo della cache delle istruzioni. - Linee guida di Google

  • I vantaggi in termini di velocità delle funzioni in linea tendono a diminuire man mano che la funzione aumenta di dimensioni.Ad un certo punto il sovraccarico della chiamata di funzione diventa piccolo rispetto all'esecuzione del corpo della funzione e il vantaggio viene perso - Fonte

  • Esistono alcune situazioni in cui una funzione in linea potrebbe non funzionare:

    • Per una funzione che restituisce valori;se esiste un'istruzione return.
    • Per una funzione che non restituisce alcun valore;se esiste un'istruzione loop, switch o goto.
    • Se una funzione è ricorsiva. -Fonte
  • IL __inline parola chiave fa sì che una funzione venga incorporata solo se si specifica l'opzione di ottimizzazione.Se viene specificato l'ottimizzazione, o meno __inline viene rispettato dipende dall'impostazione dell'opzione di ottimizzazione in linea.Per impostazione predefinita, l'opzione in linea è attiva ogni volta che viene eseguito l'ottimizzatore.Se specifichi optimization , devi specificare anche l'opzione noinline se desideri che __inline parola chiave da ignorare. -Fonte

È stato utile?

Soluzione

Vale la pena sottolineare che la parola chiave inline in realtà è solo un suggerimento per il compilatore.Il compilatore potrebbe ignorare l'inline e generare semplicemente il codice per la funzione da qualche parte.

Lo svantaggio principale delle funzioni inline è che può farlo aumentare la dimensione del tuo eseguibile (a seconda del numero di istanziazioni).Questo può essere un problema su alcune piattaforme (es.sistemi embedded), soprattutto se la funzione stessa è ricorsiva.

Consiglierei anche di creare funzioni inline molto piccolo - I vantaggi in termini di velocità delle funzioni in linea tendono a diminuire man mano che la funzione aumenta di dimensioni.Ad un certo punto il sovraccarico della chiamata di funzione diventa piccolo rispetto all'esecuzione del corpo della funzione e il vantaggio viene perso.

Altri suggerimenti

Potrebbe aumentare le dimensioni dell'eseguibile e non credo che i compilatori li rendono sempre in linea anche se hai usato la parola chiave in linea.(O è il contrario, come cosa Vaibhavdisse?...)

Penso che di solito sia OK se la funzione ha solo 1 o 2 dichiarazioni.

Modificare: Ecco cosa offre Linux Stile di codifica il documento dice a riguardo:

Capitolo 15:La malattia in linea

Sembra esserci una percezione errata comune che GCC abbia un'opzione di accelerazione "Make Me Faster" magica chiamata "Inline".Sebbene l'uso di inline possa essere appropriato (ad esempio come mezzo per sostituire le macro, vedere il capitolo 12), molto spesso non lo è.Un uso abbondante della parola chiave inline porta a un kernel molto più grande, che a sua volta rallenta il sistema nel suo insieme, a causa di un'impronta ICAche più grande per la CPU e semplicemente perché c'è meno memoria disponibile per la PageCache.Pensaci e basta;Una mancanza di Pagecache provoca una ricerca su disco, che richiede facilmente 5 milisecondi.Ci sono molti cicli della CPU che possono andare in questi 5 milisecondi.

Una ragionevole regola empirica è quella di non mettere in linea le funzioni che hanno più di 3 righe di codice in essi.Un'eccezione a questa regola sono i casi in cui un parametro è noto per essere una costante di compilazione e, a seguito di questa costante Sapere Il compilatore sarà in grado di ottimizzare la maggior parte della tua funzione al momento della compilazione.Per un buon esempio di questo caso successivo, consultare la funzione inline KMalloc ().

Spesso le persone sostengono che l'aggiunta in linea a funzioni statiche e utilizzate solo una volta è sempre una vittoria poiché non c'è compromesso di spazio.Sebbene ciò sia tecnicamente corretto, GCC è in grado di inserirli automaticamente senza aiuto e il problema di manutenzione della rimozione della linea quando un secondo utente appare supera il potenziale valore del suggerimento che dice a GCC di fare qualcosa che avrebbe fatto comunque.

Sono d'accordo con gli altri post:

  • inline potrebbe essere superfluo perché lo farà il compilatore
  • inline potrebbe gonfiare il codice

Un terzo punto è che potrebbe costringerti a esporre i dettagli di implementazione nelle tue intestazioni, ad esempio,

class OtherObject;

class Object {
public:
    void someFunc(OtherObject& otherObj) {
        otherObj.doIt(); // Yikes requires OtherObj declaration!
    }
};

Senza inline, tutto ciò di cui avevi bisogno era una dichiarazione anticipata di OtherObject.Con l'inline l'intestazione ha bisogno della definizione per l'altro oggetto.

Come altri hanno già detto, la parola chiave inline è solo un suggerimento per il compilatore.In realtà, la maggior parte dei compilatori moderni ignorerà completamente questo suggerimento.Il compilatore ha la propria euristica per decidere se incorporare una funzione e, francamente, non vuole il tuo consiglio, grazie mille.

Se davvero, davvero vuoi creare qualcosa in linea, se lo hai effettivamente profilato e osservato il disassemblaggio per assicurarti che sovrascrivere l'euristica del compilatore abbia effettivamente senso, allora è possibile:

  • In VC++, utilizza la parola chiave __forceinline
  • In GCC, utilizza __attribute__((always_inline))

La parola chiave inline ha tuttavia un secondo scopo valido: dichiarare funzioni nei file header ma non all'interno di una definizione di classe.La parola chiave inline è necessaria per indicare al compilatore di non generare più definizioni della funzione.

C'è un problema con inline: una volta definita una funzione in un file di intestazione (che implica inline, esplicito o implicito definendo il corpo di una funzione membro all'interno della classe) non esiste un modo semplice per modificarlo senza forzare gli utenti a ricompilare (al contrario di ricollegamento).Spesso questo causa problemi, soprattutto se la funzione in questione è definita in una libreria e l'intestazione fa parte della sua interfaccia.

Ne dubito.Anche il compilatore incorpora automaticamente alcune funzioni per l'ottimizzazione.

Non so se la mia risposta è correlata alla domanda ma:

Essere molto attenzione ai metodi virtuali in linea!Alcuni compilatori difettosi (ad esempio le versioni precedenti di Visual C++) generavano codice inline per metodi virtuali in cui il comportamento standard non era fare altro che scendere nell'albero dell'ereditarietà e chiamare il metodo appropriato.

L'incorporamento di funzioni più grandi può rendere il programma più grande, causando più errori nella cache e rendendolo più lento.

Decidere quando una funzione è sufficientemente piccola da consentire l'incorporamento di aumentare le prestazioni è piuttosto complicato. Guida allo stile C++ di Google consiglia solo funzioni di incorporamento di 10 righe o meno.

Dovresti anche notare che la parola chiave in linea è solo una richiesta.Il compilatore può scegliere di non incorporarlo, allo stesso modo il compilatore può scegliere di rendere inline una funzione che non hai definito come inline se ritiene che ne valga la pena.

Questa decisione viene generalmente presa in base a una serie di cose, come l'impostazione tra ottimizzazione per velocità (evita la chiamata di funzione) e ottimizzazione per dimensioni (l'incorporamento può causare un ingrossamento del codice, quindi non è ottimo per funzioni di grandi dimensioni utilizzate ripetutamente).

con il compilatore VC++ puoi ignorare questa decisione utilizzando __forceinline

Quindi in generale:Usa inline se vuoi davvero avere una funzione in un'intestazione, ma altrove non ha molto senso perché se hai intenzione di guadagnare qualcosa da essa, un buon compilatore la renderà comunque inline per te.

Un incorporamento eccessivo di funzioni può aumentare le dimensioni dell'eseguibile compilato, il che può avere un impatto negativo sulle prestazioni della cache, ma al giorno d'oggi il compilatore decide di incorporare la funzione da solo (a seconda di molti criteri) e ignora la parola chiave inline.

Tra gli altri problemi con le funzioni inline, che ho visto fortemente abusate (ho visto funzioni inline di 500 righe), ciò di cui devi essere consapevole sono:

  • creare instabilità

    • La modifica dell'origine di una funzione inline provoca la ricompilazione di tutti gli utenti dell'intestazione
    • #includec'è una perdita nel client.Questo può essere molto fastidioso se rielabori una funzione incorporata e rimuovi un'intestazione non più utilizzata su cui alcuni client hanno fatto affidamento.
  • dimensione eseguibile

    • Ogni volta che viene inserito un inline invece di un'istruzione di chiamata, il compilatore deve generare l'intero codice dell'inline.Questo va bene se il codice della funzione è breve (una o due righe), non altrettanto buono se la funzione è lunga
    • Alcune funzioni possono produrre molto più codice di quanto appaia a prima vista.Il caso in questione è un distruttore "banale" di una classe che ha molte variabili membro non pod (o due o 3 variabili membro con distruttori piuttosto disordinati).È necessario generare una chiamata per ogni distruttore.
  • tempo di esecuzione

    • questo dipende molto dalla cache della CPU e dalle librerie condivise, ma la località di riferimento è importante.Se il codice che potresti incorporare è conservato nella cache della CPU in un unico posto, un certo numero di client può trovare il codice e non subire un errore nella cache e il successivo recupero della memoria (e peggio, se dovesse accadere, un recupero del disco) .Purtroppo questo è uno di quei casi in cui è davvero necessario fare un'analisi delle prestazioni.

Lo standard di codifica in cui lavoro limita le funzioni inline a semplici setter/getter e afferma specificamente che i distruttori non dovrebbero essere inline, a meno che non si dispongano di misurazioni delle prestazioni per dimostrare che l'inlining conferisce un notevole vantaggio.

  1. Come altri hanno affermato, la funzione inline può creare un problema se il codice è grande. Poiché ogni istruzione è archiviata in una posizione di memoria specifica, il sovraccarico della funzione inline fa sì che un codice impieghi più tempo per essere eseguito.

  2. ci sono poche altre situazioni in cui la modalità inline potrebbe non funzionare

    1. non funziona in caso di funzione ricorsiva.
    2. Potrebbe anche non funzionare con la variabile statica.
    3. inoltre non funziona nel caso in cui venga utilizzato un loop, un interruttore ecc. O possiamo dirlo con più istruzioni.
    4. E la funzione main non può funzionare come funzione inline.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top