2011-01-31 14 views
14

Nel libro C++ Primer, capitolo (3), c'è il seguente ciclo che ripristina gli elementi nel vettore a zero.C++ for-loop - size_type vs. size_t

for (vector<int>::size_type ix = 0; ix ! = ivec.size(); ++ix) 
ivec[ix] = 0; 

Perché è utilizzato vector<int>::size_type ix = 0? Non possiamo dire int ix = 0? Qual è il vantaggio di utilizzare il primo modulo sul secondo?

Grazie.

risposta

15

standard C++,

 size_type | unsigned integral type | a type that can represent the size of the largest object in the 
allocation model

Poi aggiunge,

Implementazioni di contenitori descritto in questa norma internazionale sono autorizzati a supporre che il loro parametro di modello Allocatore soddisfi i seguenti due requisiti aggiuntivi rispetto a quelli riportati nella tabella 32.

  • Il typedef puntatore membri, const_pointer, size_type e difference_type sono richiesto di essere T, *, T const *, size_t, e ptrdiff_t rispettivamente

Quindi molto probabilmente, size_type è un typedef di size_t.

e lo standard davvero lo definisce come,

template <class T> 
class allocator 
{ 
    public: 
     typedef size_t size_type; 
     //....... 
}; 

Così i punti più importanti da ricordare sono:

  • size_type è unsigned integrale, mentre int è nonnecessariamenteunsigned . :-)
  • può rappresentare l'indice più grande, perché non è firmato.
+0

e quando il riferimento indica che il dimension_type di allocatore deve essere size_t e dopo C++ 14 se la dimensione() si adatta a size_t, allora il programma è mal formato, che perché al mondo abbiamo bisogno sia di size_t che di size_type? Forse qualche confusione inutile? (sappiamo che piace a C++) – user3063349

11

Sì, è possibile utilizzare int, ma solo il tipo vector<int>::size_type garantisce che il suo tipo possa essere utilizzato per indicizzare tutti gli elementi vettoriali.

Può avere o meno le stesse dimensioni di int. Ad esempio, durante la compilazione per Windows a 64 bit, int ha una larghezza di 32 bit, mentre vector<int>::size_type sarà largo 64 bit.

Invece di utilizzare il piuttosto dettagliato vector<int>::size_type, è possibile utilizzare std::size_t, poiché il primo è un typedef per quest'ultimo. Tuttavia, se dovesse capitare di cambiare il tipo di contenitore, il suo size_type potrebbe essere di un tipo diverso e potrebbe essere necessario modificare il codice se utilizza std::size_t.

+3

più di questo, size_type probabilmente non sarà mai int. Generalmente sarà size_t (unsigned int). – rkellerm

+1

Sì, intendevo che poteva avere le stesse dimensioni di un int. –

+0

La dimensione può essere di tipi diversi da 'int' o' unsigned int'? – Simplicity

9

vector<int>::size_type è un tipo che è garantito per contenere le dimensioni del più grande vector si può avere, e quindi è garantito per farvi indice di tutti gli elementi del vector (dal momento che gli indici vanno da 0 a size-1); è il tipo utilizzato per indici e dimensioni in tutti i metodi vector.

Se si dispone di molto grandi array questo può essere effettivamente rilevanti, in quanto altri tipi interi possono straripare (e se sono signed tipi cose possono diventare piuttosto strano); anche se non arriverete mai ad array così grandi che questo possa avere importanza, è fondamentalmente una cosa che riguarda la pulizia del codice; inoltre, il tuo ha lo stesso tipo di ivec.size(), quindi non ricevi avvisi per confrontare interi con segno e senza segno.

Sfondo: vector<T>::size_type è di solito un typedef per size_t (ho letto da qualche parte che in realtà lo standard implicitamente impone che sia size_t - EDIT: non è implicita a tutti, si veda la risposta @Nawaz s'), che a sua volta è il tipo di ritorno dell'operatore sizeof. Questo implicitamente dice che può contenere la dimensione per l'oggetto più grande utilizzabile in un'applicazione C++, quindi è sicuramente (solo) abbastanza grande da indicizzare array di qualsiasi tipo.

In realtà, io uso size_t (definito in <cstddef>) come indice anche per gli array in stile C, e penso che sia una buona pratica per esattamente le stesse ragioni.


Tra l'altro, si può anche dimenticare del tipo utilizzato per gli indici del tutto e basta andare con iteratori:

for (vector<int>::iterator it = ivec.begin(); it != ivec.end(); ++it) 
    *it = 0; 

o con iteratori + <algorithm>:

std::fill(ivec.begin(), ivec.end(), 0); 

Queste due opzioni funziona qualsiasi contenitore ivec, quindi non è necessario modificare nulla nel codice se si decide di cambiare il tipo di contenitore.

Con vector è anche possibile utilizzare il metodo assign (come suggerito in qualche altra risposta): dice

ivec.assign(ivec.size(), 0); 
+0

Usi 'size_t' o' std :: size_t'? ;-) – fredoverflow

+0

'std :: size_t', c'è un implicito' using namespace std; 'all'inizio di questa risposta (ma non nel mio codice)': P' –

+0

Quando dici 'vector :: size_type è un tipo che è garantito per specificare la dimensione del vettore più grande che puoi avere, puoi spiegarlo un po 'di più? Grazie – Simplicity

3

Non si deve usare int perché vector<int>::size_type è un tipo senza segno, cioè, indicizza vettore suoi elementi con un tipo senza segno. int tuttavia è un tipo firmato e il missaggio di tipi firmati e non firmati può portare a strani problemi. (Anche se non sarebbe un problema per il piccolo n nel tuo esempio.)

Nota che penso sia più chiaro usare solo size_t (in contrapposizione a T :: size_type) - meno la digitazione e dovrebbe funzionare su tutte le implementazioni.

noti inoltre che il ciclo for che avete inviato:

for(size_t ix=0; ix != ivec.size(); ++ix) ... 

sarebbe meglio scritto come:

for(size_t i=0, e=ivec.size(); i!=e; ++ix) ... 

- non c'è bisogno di chiamare size() ogni iterazione.

+0

In realtà, sarei molto sorpreso se il codice assembly per la prima versione del ciclo 'for' fosse più compatto del secondo. La chiamata a 'vector :: size()' sarà inline. –

+0

@Fred: sarei d'accordo nel caso generale. Ma per il template 'std :: vector', tutto il codice che influenza la dimensione del vettore è chiaramente visibile al compilatore, in quanto deve specializzarlo per il tipo di elemento. Ho eseguito rapidamente un test e, in effetti, non c'è differenza. –

+0

@Fred: Oh sì, in tal caso non è lo stesso, ovviamente. Ma credo che il punto @ Martin riguardasse l'ottimizzazione e la mia opinione è che questo tipo di ottimizzazione rende il codice più difficile da leggere senza influire sulle prestazioni. Se l'algoritmo lo richiede, allora quello è un altro problema. –