Inlining quasi tutti i miei metodi dell'applicazione C ++ è una buona o cattiva idea?

2

Sono abituato al codice D e Python, dove la definizione della classe contiene anche ogni definizione di metodo. Quindi è il mio stile di codifica preferito.

Mi spiace dover passare al file .cpp e usare quel nome di qualificatore lungo.

Quindi, dal momento che raramente richiamo una funzione più di 2-3 volte, non è una buona idea incorporare la maggior parte del mio codice? Il mio codice non è una libreria. È un'applicazione desktop che i matematici possono usare.

Questo ha senso per me. Va bene così? Grazie.

    
posta EnjoysMath 05.09.2018 - 02:37
fonte

3 risposte

13

Quando scrivi C ++, non scriverlo come se fosse Python o D o Java. Quelli sono lingue fondamentalmente diverse con idiomi diversi .

Quando parliamo di funzioni inline in C ++, dobbiamo distinguere due concetti correlati ma distinti:

  • inline funzioni in un'intestazione. Le definizioni di funzione all'interno di una dichiarazione di classe sono implicitamente inline . I modelli sono solitamente in linea.

    Una funzione inline (o variabile) disabilita efficacemente one-definition rule (ODR) : se il linker vede più definizioni in conflitto per la stessa funzione in diverse unità di compilazione, il linker di solito mostra un errore Ma con le funzioni inline , prometti che tutte le definizioni sono identiche. Inoltre, una funzione inline può essere chiamata solo dalla stessa unità di compilazione in cui è stata definita.

  • inlining come ottimizzazione del compilatore. La semantica di una funzione inline rende inlining possibile , ma la parola chiave inline non implica che una funzione sarà inline. Ad esempio, una funzione membro definita in linea non può essere sottolineata tramite chiamate indirette, ad esempio chiamate virtuali.

    • Puoi rendere inlining di funzioni non- inline dando loro linkage interno , tramite la parola chiave static per funzioni / variabili libere (ma non membri!) o tramite l'uso di uno spazio dei nomi anonimo.

    • È possibile utilizzare attributi specifici del compilatore. Ad esempio, __attribute__ ((always_inline)) in GCC .

Non è consigliabile definire tutte le funzioni in linea in un'intestazione.

  • Questo rallenta tempi di compilazione . Usando più unità di compilazione puoi beneficiare della compilazione incrementale . Ciò rende più piacevole il lavoro su tutti i progetti C ++ più banali. Ma se metti codice non necessario nell'intestazione, deve essere analizzato, compilato e ottimizzato nella sua interezza ogni volta. Poiché i modelli generalmente implicano definizioni incorporate in un'intestazione, questi tempi di compilazione sono una ragione per cui alcuni progetti cercano di limitare l'utilizzo dei modelli.

  • Porta a inquinamento dello spazio dei nomi e a mancanza di incapsulamento . Un sacco di codice tende ad aver bisogno di alcuni assistenti privati. In Python aggiungerei una funzione di sottolineatura al modulo, in C ++ una funzione statica o un codice in uno spazio dei nomi anonimo, in modo che siano limitati all'unità di compilazione corrente. Ma quando tutto è nelle intestazioni, hai solo una singola unità di compilazione. Tutti questi helper saranno visibili a tutto il tuo codice e in effetti non hai una struttura interna. Ciò potrebbe anche portare a conflitti di nomi.

  • Inoltre, considera in che modo includi intestazioni . Nella normale divisione di intestazione-implementazione, le intestazioni che sono necessarie solo internamente ma non per l'interfaccia pubblica del modulo possono essere incluse nel file .cpp. Ciò limita gli effetti di tale intestazione, ad esempio con qualsiasi macro o funzione globale. Questo è particolarmente importante quando si interfaccia con le librerie C. Ciò consentirà anche il collegamento tra le librerie che forniscono nomi in conflitto. Non così quando tutto il codice è nell'intestazione. Tutte le definizioni incluse saranno anche visibili in tutte le unità di compilazione in cui è inclusa l'intestazione.

  • Le definizioni in linea funzionano solo quando le tue dipendenze possono essere linearizzate, ma ad es. non per le dipendenze circolari o ricorsive (come una classe che rappresenta un nodo ad albero). Anche se si inserisce il codice in un'intestazione, potrebbe essere necessario utilizzare le dichiarazioni anticipate o definire un metodo al di fuori della dichiarazione della classe. Se questo metodo non deve essere inline , non ottieni nulla dal definirlo nell'intestazione.

Se non ti piace dover scambiare spesso intestazioni e file di implementazione, ti suggerisco di utilizzare un IDE che ti consenta di passare più facilmente tra le dichiarazioni e le definizioni corrispondenti.

Sì, C / C ++ può essere una lingua super fastidiosa con tutto il loro storico cruft. E sì, il codice Java tende ad essere più piacevole da leggere. Ma non otterrai alcun beneficio dal provare a scrivere in C ++ come se fosse Java. Stavi semplicemente rinunciando ai benefici che C ++ può offrire. Allo stesso modo, il C ++ moderno evita la creazione di oggetti con new , dato che effettivamente abbandona RAII.

    
risposta data 05.09.2018 - 09:14
fonte
4

Se per integrazione intendi la funzione inline , non è necessario:

  • i compilatori mainstream ora eseguono l'ottimizzazione globale e lo faranno automaticamente per te se ha un reale vantaggio in termini di prestazioni.
  • la dicitura dello standard mostra che non influenzerai molto ciò che farà il compilatore:

    An implementation is not required to perform this inline substitution at the point of call

  • La differenza principale è se si definisce una funzione in un'intestazione. Con la parola chiave inline , il compilatore permetterà di includere l'intestazione in più punti, essendo inteso che è la stessa funzione ovunque. Senza inline , potresti rompere la regola di definizione unica (ODR) se la stessa intestazione è inclusa in unità diverse.

Se per integrazione si intende inserire la definizione della funzione membro all'interno della definizione della classe nell'intestazione, questa pratica non è quella consigliata. Non interromperà la regola ODR se viene utilizzata la stessa identica sequenza di token per la stessa classe in ciascuna unità di compilazione. Ma ci sono un paio di cose che sono più difficili da fare (specialmente se ci sono alcune mutue dipendenze tra due classi). Separare la definizione della classe dalla sua implementazione ha il vantaggio di incoraggiare l'incapsulamento.

    
risposta data 05.09.2018 - 08:56
fonte
1

Mi piace molto un file di intestazione ben documentato, che mi dice solo quello che voglio sapere: nomi di classi e metodi, quali sono i metodi che si prefiggono di fare. Non voglio vedere il tuo codice sorgente. Rende solo più difficile leggere le cose che voglio.

Swift lo fa bene: scrivi il codice nel modo desiderato, l'IDE genera i file di intestazione se voglio vederli e contengono solo cose di interesse (come nessun metodo o proprietà privata).

    
risposta data 05.09.2018 - 11:23
fonte

Leggi altre domande sui tag