Domanda

Supponiamo che un file di intestazione definisca un modello di funzione. Supponiamo ora due file di implementazione #include questa intestazione e ognuno di essi ha una chiamata al modello di funzione. In entrambi i file di implementazione il modello di funzione è istanziato con lo stesso tipo.

// header.hh
template <typename T>
void f(const T& o)
{
    // ...
}

// impl1.cc
#include "header.hh"

void fimpl1()
{
    f(42);
}

// impl2.cc
#include "header.hh"

void fimpl2()
{
    f(24);
}

Ci si può aspettare che il linker si lamenti di più definizioni di f () . In particolare, se f () non sarebbe un modello, sarebbe effettivamente così.

  • Come mai il linker non si lamenta di più definizioni di f () ?
  • È specificato nello standard che il linker deve gestire questa situazione con garbo? In altre parole, posso sempre contare su programmi simili ai precedenti per compilare e collegare?
  • Se il linker può essere abbastanza intelligente da chiarire una serie di istanze di template di funzione, perché non può fare lo stesso per le funzioni regolari, dato che sono identiche come nel caso dei template di funzione istanziati?
È stato utile?

Soluzione

Al fine di supportare C ++, il linker è abbastanza intelligente da riconoscere che hanno tutti la stessa funzione e butta fuori tutti tranne uno.

EDIT: chiarimento: Il linker non confronta i contenuti delle funzioni e determina che sono uguali. Le funzioni basate su modelli sono contrassegnate come tali e il linker riconosce di avere le stesse firme.

Altri suggerimenti

Il manuale del compilatore Gnu C ++ contiene una buona discussione di questo . Un estratto:

  

I modelli C ++ sono la prima lingua   caratteristica per richiedere più intelligenza   dall'ambiente di solito   trova su un sistema UNIX. In qualche modo il   compilatore e linker devono essere sicuri   che si verifica ogni istanza del modello   esattamente una volta nell'eseguibile, se lo è   è necessario e per niente altrimenti.   Ci sono due approcci di base a questo   problema, che sono indicati come   Modello Borland e modello Cfront.

     

Modello Borland

     

Borland C ++ ha risolto il modello   problema di istanza aggiungendo il   codice equivalente di blocchi comuni a   il loro linker; il compilatore emette   istanze del modello in ogni traduzione   unità che li utilizza e il linker   li fa collassare insieme. Il vantaggio   di questo modello è solo il linker   deve considerare i file oggetto   loro stessi; non c'è esterno   complessità di cui preoccuparsi. Questo   lo svantaggio è che il tempo di compilazione   viene aumentato perché il codice modello   viene compilato ripetutamente. Codice   scritto per questo modello tende a   includere definizioni di tutti i modelli   nel file di intestazione, poiché devono essere   visto per essere istanziato.

     

Modello Cfront

     

Il traduttore AT & amp; T C ++, Cfront,   risolto l'istanza del modello   problema creando la nozione di a   repository di modelli, un automaticamente   luogo mantenuto dove modello   le istanze sono memorizzate. Un più moderno   la versione del repository funziona come   segue: Come singoli file oggetto   vengono creati, il compilatore ne posiziona uno   definizioni dei modelli e   istanze incontrate nel   repository. Al momento del collegamento, il collegamento   wrapper aggiunge gli oggetti in   repository e compila ogni necessario   istanze che non erano in precedenza   emessa. I vantaggi di questo modello   sono la velocità di compilazione più ottimale e   la capacità di utilizzare il linker di sistema;   per implementare il modello Borland a   anche il fornitore del compilatore deve sostituire   il linker. Gli svantaggi sono   complessità notevolmente aumentata, e quindi   potenziale errore; per un po 'di codice   questo può essere altrettanto trasparente, ma   in pratica può essere molto difficile   per creare più programmi in uno   directory e un programma in più   le directory. Codice scritto per questo   il modello tende a separare le definizioni di   modelli di membri non inline in a   file separato, che dovrebbe essere   compilato separatamente.

     

Se usato con GNU ld versione 2.8 o   in seguito un sistema ELF come   GNU / Linux o Solaris 2 o su   Microsoft Windows, G ++ supporta il   Modello Borland. Su altri sistemi, G ++   non implementa né il modello automatico.

Questo è più o meno un caso speciale solo per i modelli.

Il compilatore genera solo le istanze del modello effettivamente utilizzate. Poiché non ha alcun controllo su quale codice verrà generato da altri file di origine, deve generare il codice modello una volta per ogni file, per assicurarsi che il metodo venga generato affatto.

Poiché è difficile risolverlo (lo standard ha una parola chiave extern per i modelli, ma g ++ non lo implementa) il linker accetta semplicemente le definizioni multiple.

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