Scelta del tipo di variabili indice

11

Usiamo il tipo Integer per rappresentare le variabili di indice il più delle volte. Ma in alcune situazioni, siamo costretti a scegliere

std::vector<int> vec;
....

for(int i = 0; i < vec.size(); ++i)
....

Questo farà sì che il compilatore aumenti l'avviso che usa in modo misto le variabili firmate / non firmate. se faccio la variabile index come for( size_t i = 0; i < vec.size(); i++ ) , (o unsigned int ) risolverà i problemi.

Quando è più specifico usare i tipi di Windows, la maggior parte delle API di Windows hanno a che fare con DWORD (che è stato digitato a macchina come unsigned long).

Quindi, quando uso un'iterazione simile, causerò di nuovo lo stesso avvertimento. Ora se lo riscrivo come

DWORD dwCount;
....

for(DWORD i = 0; i < dwCount; ++i)
....

Trovo che sia un po 'strano Potrebbe essere il problema con le percezioni.

Sono d'accordo sul fatto che dovremmo utilizzare lo stesso tipo di variabile di indice per evitare che i problemi di intervallo possano verificarsi con le variabili dell'indice. Ad esempio, se utilizziamo

_int64 i64Count; // 
....

for(_int64 i = 0; i < i64Count; ++i)
....

Ma nel caso di DWORD, o interi senza segno, ci sono problemi nel riscriverlo come

for(int i = 0; (size_t)i < vec.size(); ++i)

In che modo la maggior parte delle persone lavora con problemi simili?

    
posta sarat 30.08.2011 - 06:51
fonte

6 risposte

11

vector ha un typedef che ti dice il tipo corretto da usare: -

for(std::vector<int>::size_type i = 0; i < thing.size(); ++i)
{
}

È quasi sempre definito come size_t, ma non puoi fidarti di quello

    
risposta data 30.08.2011 - 12:28
fonte
4
std::vector<int> vec;

for(int i = 0; i < vec.size(); ++i)

Utilizza un iteratore per questo, non un ciclo for .

Per gli altri, a condizione che il tipo di variabile sia della stessa dimensione, static_cast dovrebbe funzionare bene (cioè DWORD in int16_t )

    
risposta data 30.08.2011 - 08:30
fonte
3

Il caso che hai descritto è una delle cose che non mi piace anche in C ++. Ma ho imparato a conviverci, usando

for( size_t i = 0; i < vec.size(); i++ )

o

for( int i = 0; i < (int)vec.size(); i++ )

(ovviamente, quest'ultimo solo quando non c'è il rischio di ottenere un overflow int).

    
risposta data 30.08.2011 - 14:01
fonte
3

Il motivo per cui ti avverte del confronto tra firmato e non firmato è perché il valore firmato verrà probabilmente convertito in non firmato, il che potrebbe non essere quello che ti aspetti.

Nel tuo esempio (confrontando int con size_t ), int sarà convertito implicitamente in size_t (a meno che int abbia in qualche modo un intervallo maggiore di size_t ). Pertanto, se int è negativo, sarà probabilmente maggiore del valore con cui lo stai confrontando a causa di wraparound. Questo non sarà un problema se il tuo indice non è mai negativo, ma riceverai comunque questo avviso.

Utilizza invece un tipo senza segno (come unsigned int , size_t o, come John B consiglia , std::vector<int>::size_type ) per la variabile dell'indice:

for(unsigned int i = 0; i < vec.size(); i++)

Fai attenzione quando esegui il conto alla rovescia, però:

for(unsigned int i = vec.size()-1; i >= 0; i--) // don't do this!

Quanto sopra non funzionerà perché i >= 0 è sempre true quando i non è firmato. Invece, usa " operatore freccia "per cicli che contano:

for (unsigned int i = vec.size(); i-- > 0; )
    vec[i] = ...;

Come indicano altre risposte, normalmente si desidera utilizzare un iteratore per attraversare un vector . Ecco la sintassi C ++ 11:

for (auto i = vec.begin(); i != vec.end(); ++i)
    
risposta data 30.08.2011 - 15:03
fonte
2

Una nuova opzione per C ++ 11, puoi fare cose come la seguente

for(decltype(vec.size()) i = 0; i < vec.size(); ++i) {...}

e

for(decltype(dWord) i = 0; i < dWord; ++i) {...}

Anche se ripete un po 'di più rispetto al ciclo di base, non è quasi altrettanto prolisso di pre-'11 modi di specificare i valori, e l'uso di questo modello in modo coerente funzionerà per la maggior parte, se non tutti, i termini possibili vorresti confrontarti, il che lo rende ottimo per il refactoring del codice. Funziona anche per casi semplici come questo:

int x = 3; int final = 32; for(decltype(final) i = x; i < final; ++i)

Inoltre, mentre dovresti usare auto ogni volta che imposti i su un valore intelligente (come vec.begin() ), decltype funziona quando sei impostato su una costante come zero, dove auto sarebbe solo risolvilo in int perché 0 è un valore letterale intero semplice.

Per essere onesti, mi piacerebbe vedere un meccanismo di compilazione per estendere la determinazione del tipo auto per gli incrementatori di loop per esaminare il valore confrontato con.

    
risposta data 15.12.2011 - 21:00
fonte
1

Uso un cast per int, come in for (int i = 0; i < (int)v.size(); ++i) . Sì, è brutto. Do la colpa al design stupido della libreria standard in cui hanno deciso di utilizzare numeri interi senza segno per rappresentare le dimensioni. (Al fine di ... cosa? Estendere l'intervallo di un bit?)

    
risposta data 31.08.2011 - 08:11
fonte

Leggi altre domande sui tag