Le librerie solo intestazione sono più efficienti?


49

ipotesi

  1. Uno dei vantaggi delle librerie solo intestazione per C ++ è che non devono essere compilate separatamente.

  2. In C e C ++ inlineha senso solo se la funzione è definita in un file di intestazione *.

  3. Tradizionalmente, in C, è stato utilizzato il layout .c / .h, dove l'intestazione rappresenta l'interfaccia pubblica minima dell'unità di traduzione. Allo stesso modo, .cpp / hpp.

Domanda

Le librerie di sola intestazione sono generalmente più efficienti in termini di codice e tempo di esecuzione rispetto al layout tradizionale? Se è così, è a causa di approfonditi inline o altre ottimizzazioni?

* - la definizione della funzione in un'intestazione consente al compilatore di vedere l'implementazione durante la compilazione di qualsiasi unità di traduzione e praticamente rende possibile l'inserimento del codice


2
Sareste sorpresi di quanto un sacco di moderni linker C ++ (GCC, MSVC, ICC, ecc.) Possano incorporare il codice in unità di traduzione separate. Direi "generalmente no" dal punto di vista dell'efficienza dato il numero di volte in cui l'ottimizzazione dei linker ha sfidato le mie aspettative e sono comunque riusciti a integrarmi (escludendo i contesti dylib in cui l'inserimento in un'intestazione o la fornitura dell'implementazione in una libreria separata collegata staticamente può aiutare) . Tuttavia, le librerie di sola intestazione, a condizione che siano stabili sia nell'interfaccia che nell'implementazione, possono essere sexy a causa della facilità con cui possono essere distribuite in nuovi progetti.

1
Non so che questo merita una risposta completa, ma un enorme vantaggio delle librerie solo intestazione è la facilità di installazione e utilizzo: Download, #include "lib.h (pp)", fatto.
WeRelic,

Risposte:


45

Uno dei vantaggi delle librerie solo intestazione per C ++ è che non devono essere compilate separatamente

No, questo non è un vantaggio, al contrario: la parte principale della libreria deve essere compilata tutte le volte che viene inclusa, non solo una volta. Ciò in genere aumenta i tempi di compilazione. Tuttavia, se ti riferisci ai vantaggi elencati qui in Wikipedia : quell'articolo parla di minori spese amministrative relative all'intero processo di costruzione, confezionamento e distribuzione.

In C e C ++ inline ha senso solo se la funzione è definita in un file di intestazione *

Questo dipende dal sistema compilatore / linker, ma suppongo che per la maggior parte dei compilatori C e C ++ esistenti ciò sia vero.

Tradizionalmente, in C, è stato utilizzato il layout .c / .h, dove l'intestazione rappresenta l'interfaccia pubblica minima dell'unità di traduzione. Allo stesso modo, .cpp / hpp.

Questo è per lo più corretto. Le intestazioni di classe C ++ spesso contengono più dell'interfaccia pubblica minima: in genere contengono anche molte cose private. Per mitigare questo, vengono usate cose come il linguaggio PIMPL . Questo è qualcosa come "l'opposto" di una libreria di sola intestazione, cerca di minimizzare il contenuto dell'intestazione necessario.

Ma per rispondere alla tua domanda principale: questo è un compromesso. Più codice libreria viene inserito nei file di intestazione, più il compilatore ha la possibilità di ottimizzare il codice per la velocità (se ciò accade davvero o se l'incremento è notevole, è una domanda completamente diversa). D'altra parte, troppo codice nelle intestazioni aumenta il tempo di compilazione. Soprattutto nei grandi progetti C ++ questo può diventare un problema serio, vedi "Progettazione software C ++ su larga scala" di John Lakos - sebbene il libro sia un po 'obsoleto e alcuni dei problemi descritti in esso siano affrontati dai compilatori moderni, le idee generali / le soluzioni sono ancora valide.

In particolare, quando non si utilizza una libreria stabile (di terze parti), ma si stanno sviluppando le proprie librerie durante il progetto, i tempi di compilazione diventano evidenti. Ogni volta che cambi qualcosa nella libreria, devi cambiare un file di intestazione, che causerà una ricompilazione e un collegamento di tutte le unità dipendenti.

IMHO la popolarità delle librerie solo intestazione è causata dalla popolarità della meta programmazione dei template. Per la maggior parte dei compilatori, le librerie basate su modelli devono essere solo intestazione poiché il compilatore può avviare il processo di compilazione principale solo quando vengono forniti i parametri di tipo e per compilazione completa e ottimizzazione il compilatore deve vedere "entrambi in una volta" - il codice della libreria più il modello valori dei parametri. Ciò rende impossibile (o almeno difficile) produrre unità di compilazione "precompilate" per tale libreria.


6
Quindi, in breve, le librerie solo intestazione sono più convenienti piuttosto che più efficienti ; e poiché C ++ non ha alcun gestore di pacchetti standard, questo aiuta a favorire l'adozione.
Matthieu M.,

6
@MatthieuM: no, a volte il codice compilato potrebbe in effetti essere più efficiente, e per le librerie di template il design solo dell'intestazione non è in genere una questione di convenienza. E i tempi di compilazione aumentati non sono sicuramente più convenienti.
Doc Brown,

Avere il codice attivo nelle intestazioni potrebbe effettivamente portare a un codice compilato più efficiente, tuttavia ciò non richiede di avere tutto il codice nelle intestazioni ed è quindi indipendente, IMHO, dalle librerie solo di intestazione.
Matthieu M.,

1
@MatthieuM .: questo è sicuramente corretto, tuttavia credo che il termine "più conveniente" non descriva bene il caso.
Doc Brown,

3
Ho lavorato su un grande progetto incorporato sopra un sistema operativo più vecchio e snello per il mio precedente datore di lavoro, e in quei casi posso attestare il dolore di lunghi tempi di compilazione. Chiunque fosse sorpreso a riempire troppo i file di intestazione sarebbe trattato senza pietà.
Fred Thomsen il

15

Bene, prima demoliamo alcuni dei tuoi presupposti:

  1. Uno dei vantaggi delle librerie solo intestazione per C ++ è che non devono essere compilate separatamente.

Compilare le cose separatamente significa potenzialmente non dover ricompilare tutto se cambia solo una parte.
Quindi, uno svantaggio anziché un vantaggio.

  1. In C e C ++ inline ha senso solo se la funzione è definita in un file di intestazione *.

Sì, l'unico effetto inlinerimasto è l'eccezione alla regola a una definizione .
Guai a te se quelle definizioni sono comunque diverse in ogni modo.

Quindi, se una funzione è interna a un'unità di compilazione, contrassegnarla static. Ciò rende anche più probabile l'allineamento, poiché la funzione deve essere disponibile per incorporarla.
Tuttavia, dai un'occhiata all'ottimizzazione del tempo di collegamento, come supportato da almeno MSVC ++, gcc e clang.

  1. Tradizionalmente, in C, è stato utilizzato il layout .c / .h, dove l'intestazione rappresenta l'interfaccia pubblica minima dell'unità di traduzione. Allo stesso modo, .cpp / hpp.

Bene, presentare solo l'interfaccia minima è certamente uno degli obiettivi, per ottenere una maggiore stabilità API e ABI e ridurre al minimo i tempi di compilazione.

Soprattutto le classi C ++ non sono realmente orientate a questo, poiché tutti i bit privati ​​penetrano nell'intestazione, così come quelli protetti, indipendentemente dal fatto che tu voglia derivarne o meno.

Il modello di progettazione PIMPL serve a ridurre tali dettagli.

La parte in cui la separazione dell'interfaccia e l'implementazione falliscono completamente in C ++ sono i modelli.
Il comitato ha provato a fare qualcosa con i modelli esportati , ma questo è stato abbandonato perché troppo complicato e non funzionante.

Ora stanno lavorando su un sistema di moduli adeguato , anche se è lento. Ciò riduce notevolmente i tempi di compilazione e dovrebbe anche aumentare la stabilità API e ABI diminuendo la loro superficie.

Le librerie di sola intestazione sono generalmente più efficienti in termini di codice e tempo di esecuzione rispetto al layout tradizionale? Se è così, è a causa di approfonditi inline o altre ottimizzazioni?

Le librerie solo intestazione possono essere più efficienti in termini di dimensioni del codice e tempi di esecuzione, anche se ciò dipende dal fatto che la libreria sia condivisa, da quanto ne viene utilizzata, in quali modi e se l'inline dimostra una vittoria decisiva in quel caso specifico.

E il motivo per cui l'allineamento è così importante per l'ottimizzazione non è perché l'allineamento in sé stesso è un grande impulso, ma a causa delle opportunità di propagazione costante e di ulteriore ottimizzazione si apre.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.