2013-03-11 16 views
11

Una volta mi è stata posta una domanda a sorpresa in un colloquio di lavoro: una classe basata su modelli richiede più memoria di un'altra classe che è identica ma non basata su modelli? La mia risposta era no, ma il fatto che abbia posto la domanda significa che probabilmente c'è un caso in cui c'è. O voleva davvero scopare con me. Quale sarebbe il caso in cui una classe basata su modelli richiederebbe più memoria?Una classe basata su modello è più grande della classe non modello utilizzando lo stesso tipo?

+7

Ho il sospetto che Il fatto che abbia posto la domanda indica che ci sono persone che * pensano * che un modello di classe abbia più memoria di una classe non modello. –

+2

no, non lo è. ci vuole esattamente lo stesso. –

+0

Sì, 'modello di classe 'richiede più memoria di una classe normale, ma è nel file di origine perché è richiesto più testo. – iammilind

risposta

15

La prima cosa è chiarire qual è il significato della domanda. Se la domanda è se gli oggetti del tipo saranno più grandi (ad esempio sizeof(T<int>) > sizeof(T_int)), la risposta è no. Se la domanda riguarda l'impronta binaria dell'applicazione stessa, incluso il codice per le funzioni, la risposta è che la dimensione complessiva del programma potrebbe effettivamente essere inferiore nel caso di un modello, poiché solo le funzioni membro utilizzate verranno assegnate a compilato (se non esplicitamente istanziato). Sebbene alla fine della giornata, il linker potrebbe potenzialmente scartare anche i membri non utilizzati dalla versione non-template.

Esiste un termine comune: codice bloat utilizzato per fare riferimento all'esplosione del codice generato dai modelli. Il termine si riferisce al fatto che ogni diversa istanziazione di un modello genererà le proprie funzioni e che può far sì che più funzioni siano presenti nell'eseguibile rispetto a un insieme più piccolo di funzioni non modello per le quali sono consentite le conversioni degli argomenti.

consideri una possibile interfaccia per un modello di vettore:

template <typename T> 
class Vector { 
    template <typename U> void push_back(U u); 
//.... 

Per ogni chiamata a push_back con un diverso tipo di argomento, una nuova funzione verrà generato, quindi ci sarà una funzione per Vector<int>::push_back('a') e un altro per Vector<int>::push_back(1). Confrontalo con l'interfaccia di std::vector in cui la funzione membro non è un modello e il chiamante esegue la conversione del tipo.

Sebbene questa possa essere una fonte di file eseguibili di maggiori dimensioni, non ritengo che ciò sia ciò che è stato chiesto. In particolare, per un tipo di modello e il tipo equivalente non di modello per il tipo particolare istanziato, il codice generato dovrebbe essere equivalente (ignorando il fatto che i nomi storti tendono ad essere più grandi per i modelli :))

+0

+1 Bella risposta. Spiegato quasi tutti i punti. – Nawaz

+0

@Nawaz: Ho appena scaricato ciò che mi è venuto in mente considerando l'eseguibile finale (nel livello intermedio, per un modello il codice prima del collegamento potrebbe avere più definizioni di esattamente le stesse funzioni membro in ogni unità di traduzione, ma queste vengono scartate al momento del collegamento). Se hai in mente qualcos'altro per completare * quasi tutti *, sono interessato a sentirli :) –

+0

No. Non ho nient'altro nella mia mente. Hai detto praticamente tutto quello che potevo pensare (al momento). Ho detto "quasi tutti" esattamente per la stessa ragione per cui non ho detto "tutti". Penso che sia saggio essere aperti alle possibilità. :-) – Nawaz

5

La risposta è NO, per quanto riguarda la memoria. Voglio dire, non deve necessariamente prendere più memoria, anche se qualche malvagio potrebbe scrivere un modello di classe solo per provare il suo punto che la versione del modello di classe richieda più memoria.

Tuttavia, il codice sorgente del modello di classe potrebbe essere maggiore (o minore per quella materia) rispetto a versioni non classificate di un clas per un valore particolare del/i parametro/i di tipo.

template<typename T> 
struct point_t 
{ 
    T x, y, z; 
}; 

struct point_int 
{ 
    int x, y, z; 
}; 

std::cout << (sizeof(point_int) == sizeof(point_t<int>)) << std::end; 

Stamperà true (o 1).

Nota solo che il layout di memoria di point_int e point_t<int> sarà lo stesso. Così si può anche lanciare in questo modo:

point_t<int> pt {10, 20, 30}; 

point_int pi = *reinterpret_cast<point_int*>(&pt); 

std::cout << "{" << pi.x <<"," << pi.y <<"," << pi.z << "}" << std::endl; 

Si stamperà {10, 20, 30}.

Speranza che aiuta.

2

Il modello viene sostituito con i valori reali in ogni posizione in cui è stato rifrato in fase di compilazione. quindi se si dispone di una classe template dicono:

public List<T> 
{ 
    public T* MyT; 
    ... 
} 

e il codice utilizza con un tipo specifico dicono: List, di quello che sta realmente accadendo che questo codice viene utilizzato:

public List<Point> 
{ 
public Point *MyT; 
.... 
} 

Quindi è essenzialmente la stessa dimensione di qualsiasi altra classe non modello.

Problemi correlati