Domanda

Ho una classe che ha molte piccole funzioni. Per piccole funzioni intendo funzioni che non eseguono alcuna elaborazione ma restituiscono solo un valore letterale. Qualcosa del tipo:

string Foo::method() const{
    return "A";
}

Ho creato un file header " Foo.h " e file sorgente " Foo.cpp " ;. Ma poiché la funzione è molto piccola, sto pensando di inserirla nel file di intestazione stesso. Ho le seguenti domande:

  1. Vi sono problemi di prestazioni o altri problemi se inserisco queste definizioni delle funzioni nel file di intestazione? Avrò molte funzioni come questa.
  2. La mia comprensione è al termine della compilazione, il compilatore espanderà il file di intestazione e lo posizionerà dove è incluso. È corretto?
È stato utile?

Soluzione

Se la funzione è piccola (la possibilità di cambiarla spesso è bassa) e se la funzione può essere inserita nell'intestazione senza includere miriadi di altre intestazioni (poiché la funzione dipende da esse), è perfettamente valida fare così. Se li dichiarate in linea all'esterno, il compilatore è tenuto a dargli lo stesso indirizzo per ogni unità di compilazione:

headera.h :

inline string method() {
    return something;
}

Le funzioni membro sono inline implicite a condizione che siano definite all'interno della loro classe. Lo stesso vale per loro: se possono essere inseriti nell'intestazione senza problemi, puoi davvero farlo.

Poiché il codice della funzione è inserito nell'intestazione e visibile, il compilatore è in grado di incorporare le chiamate verso di loro, cioè inserendo il codice della funzione direttamente nel sito di chiamata (non tanto perché lo hai messo in linea prima di esso , ma di più perché il compilatore decide in questo modo, però. Mettere inline è solo un suggerimento per il compilatore). Ciò può comportare un miglioramento delle prestazioni, perché il compilatore ora vede dove gli argomenti corrispondono alle variabili locali alla funzione e dove l'argomento non si alias l'altro - e, ultimo ma non meno importante, l'allocazione del frame della funzione non è più necessaria.

  

La mia comprensione è al termine della compilazione, il compilatore espande il file di intestazione e lo posiziona dove è incluso. È corretto?

Sì, è corretto. La funzione sarà definita in ogni punto in cui includi la sua intestazione. Il compilatore si preoccuperà di inserire solo una sua istanza nel programma risultante, eliminando le altre.

Altri suggerimenti

A seconda del compilatore e delle sue impostazioni, può eseguire una delle seguenti operazioni:

  • Potrebbe ignorare la parola chiave incorporata (esso è solo un suggerimento per il compilatore, non un comando) e generare autonomo funzioni. Potrebbe farlo se il tuo le funzioni superano un compilatore dipendente soglia di complessità. per esempio. troppi loop nidificati.
  • Potrebbe decidere rispetto al tuo stand-alone la funzione è un buon candidato per espansione in linea.

In molti casi, il compilatore è in una posizione molto migliore per determinare se una funzione deve essere incorporata rispetto a te, quindi non ha senso ripensarla. Mi piace usare la linea implicita quando una classe ha molte piccole funzioni solo perché è conveniente avere l'implementazione proprio lì nella classe. Questo non funziona così bene per funzioni più grandi.

L'altra cosa da tenere a mente è che se si esporta una classe in una libreria DLL / condivisa (non è una buona idea IMHO, ma le persone lo fanno comunque) è necessario fare molta attenzione con le funzioni incorporate. Se il compilatore che ha creato la DLL decide che una funzione dovrebbe essere integrata, hai un paio di potenziali problemi:

  1. Il compilatore che crea il programma l'utilizzo della DLL potrebbe decidere di non farlo incorporare la funzione così sarà generare un riferimento simbolo a funzione che non esiste e il La DLL non verrà caricata.
  2. Se si aggiorna la DLL e si modifica il funzione incorporata, il programma client utilizzerà ancora la versione precedente di quella funzione poiché la funzione è stato inserito nel codice client.

Ci sarà un aumento delle prestazioni perché l'implementazione nei file di intestazione è implicitamente incorporata. Come hai detto, le tue funzioni sono piccole, le operazioni in linea saranno molto utili per il tuo IMHO.

Anche quello che dici sul compilatore è vero. Non c'è differenza per il compilatore & # 8212; diverso dall'inline & # 8212; tra il codice nel file di intestazione o il file .cpp .

  1. Se le tue funzioni sono così semplici, rendile in linea e dovrai comunque inserirle nel file di intestazione. A parte questo, tutte le convenzioni sono proprio questo: convenzioni.

  2. Sì, il compilatore espande il file di intestazione dove incontra le istruzioni #include.

Dipende dagli standard di codifica che si applicano nel tuo caso ma:

Le piccole funzioni senza loop e nient'altro dovrebbero essere definite per migliorare le prestazioni (ma un codice leggermente più grande - importante per alcune applicazioni vincolate o incorporate).

Se hai il corpo della funzione nell'intestazione, la avrai automaticamente in linea (d) (che è una buona cosa quando si tratta di velocità).

Prima che il file oggetto venga creato dal compilatore, viene chiamato il preprocessore (opzione -E per gcc) e il risultato viene inviato al compilatore che crea l'oggetto fuori codice.

Quindi la risposta più breve è:

- Dichiarare le funzioni nell'intestazione è buono per la velocità (ma non per lo spazio) -

  

C ++ non ti lamenterà se lo fai, ma in generale, non dovresti & # 8217; t.

     

quando #includi un file, l'intero contenuto del file incluso viene inserito nel punto di inclusione. Ciò significa che qualsiasi definizione inserita nell'intestazione viene copiata in ogni file che include quell'intestazione.

     

Per i piccoli progetti, questo non è probabilmente un grosso problema. Ma per i progetti più grandi, ciò può richiedere molto più tempo per la compilazione (poiché lo stesso codice viene ricompilato ogni volta che viene incontrato) e potrebbe gonfiare in modo significativo le dimensioni dell'eseguibile. Se si modifica una definizione in un file di codice, è necessario ricompilare solo quel file .cpp. Se si modifica una definizione in un file di intestazione, tutti i file di codice che includono l'intestazione devono essere ricompilati. Una piccola modifica può farti ricompilare l'intero progetto!

     

A volte vengono fatte eccezioni per funzioni banali che è improbabile che cambino (ad es. dove la definizione della funzione è una riga).

Fonte: http://archive.li/ACYlo (versione precedente del capitolo 1.9 su learncpp.com )

Dovresti usare le funzioni incorporate. Leggi questo Funzioni in linea per una migliore comprensione e i compromessi coinvolti .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top