Risposte:
Preferirei it - vec.begin()
precisamente per la ragione opposta fornita da Naveen: quindi non si comporterebbe se cambiassi il vettore in un elenco. Se lo fai durante ogni iterazione, potresti facilmente trasformare un algoritmo O (n) in un algoritmo O (n ^ 2).
Un'altra opzione, se non si salta nel contenitore durante l'iterazione, sarebbe quella di mantenere l'indice come contatore del secondo loop.
Nota: it
è un nome comune per un iteratore contenitore, std::container_type::iterator it;
.
it
?
std::container_type::iterator it;
std::list
non offre accesso diretto agli elementi in base alla loro posizione, quindi se non puoi farlo list[5]
, non dovresti essere in grado di farlo list.begin() + 5
.
Preferirei std::distance(vec.begin(), it)
perché mi permetterà di cambiare il contenitore senza alcuna modifica del codice. Ad esempio, se si decide di utilizzare al std::list
posto del std::vector
quale non viene fornito un iteratore ad accesso casuale, il codice verrà comunque compilato. Poiché std :: distance raccoglie il metodo ottimale in base ai tratti dell'iteratore, non si avrà alcun degrado delle prestazioni.
vec
è una cattiva notizia. Se il codice è stato riscritto per essere generico, prendendo il tipo di contenitore come parametro modello, è allora che possiamo (e dovremmo) parlare della gestione di iteratori ad accesso non casuale ;-)
vec
è anche una brutta notizia.
Come hanno dimostrato UncleBens e Naveen, ci sono buone ragioni per entrambi. Quale è "migliore" dipende dal comportamento che desideri: vuoi garantire un comportamento a tempo costante o vuoi che ritorni al tempo lineare quando necessario?
it - vec.begin()
richiede tempo costante, ma operator -
è definito solo su iteratori ad accesso casuale, quindi il codice non verrà compilato affatto con iteratori elenco, ad esempio.
std::distance(vec.begin(), it)
funziona per tutti i tipi di iteratore, ma sarà un'operazione a tempo costante solo se utilizzato su iteratori ad accesso casuale.
Nessuno dei due è "migliore". Usa quello che fa quello che ti serve.
Mi piace questo: it - vec.begin()
perché per me dice chiaramente "distanza dall'inizio". Con gli iteratori siamo abituati a pensare in termini di aritmetica, quindi il -
segno è l'indicatore più chiaro qui.
distance
?
it++
e non qualcosa del genere std::increment(it)
, no? Non sarebbe altrettanto meno chiaro?
++
operatore è definito come parte delle sequenze STL come come incrementiamo l'iteratore. std::distance
calcola il numero di elementi tra il primo e l'ultimo elemento. Il fatto che l' -
operatore funzioni è semplicemente una coincidenza.
Se hai già limitato / codificato il tuo algoritmo all'utilizzo di un std::vector::iterator
e std::vector::iterator
solo, non importa quale metodo finirai per utilizzare. Il tuo algoritmo è già concretizzato oltre il punto in cui la scelta dell'altro può fare la differenza. Entrambi fanno esattamente la stessa cosa. È solo una questione di preferenze personali. Personalmente userei la sottrazione esplicita.
Se, d'altra parte, vuoi mantenere un più alto grado di generalità nel tuo algoritmo, vale a dire, per consentire la possibilità che un giorno in futuro possa essere applicato ad un altro tipo di iteratore, allora il metodo migliore dipende dal tuo intento . Dipende da quanto restrittivo vuoi essere rispetto al tipo di iteratore che può essere usato qui.
Se usi la sottrazione esplicita, il tuo algoritmo sarà limitato a una classe piuttosto ristretta di iteratori: iteratori ad accesso casuale. (Questo è ciò che ottieni ora std::vector
)
Se lo usi distance
, il tuo algoritmo supporterà una classe molto più ampia di iteratori: input iteratori.
Naturalmente, il calcolo distance
per gli iteratori ad accesso non casuale è in genere un'operazione inefficiente (mentre, ancora una volta, per quelli ad accesso casuale è efficiente quanto la sottrazione). Sta a te decidere se il tuo algoritmo ha senso per iteratori ad accesso non casuale, in termini di efficienza. Se la conseguente perdita di efficienza è devastante al punto da rendere il tuo algoritmo completamente inutile, quindi dovresti attenersi meglio alla sottrazione, vietando così gli usi inefficienti e costringendo l'utente a cercare soluzioni alternative per altri tipi di iteratori. Se l'efficienza con iteratori ad accesso casuale non è ancora nell'intervallo utilizzabile, è necessario utilizzare distance
e documentare il fatto che l'algoritmo funziona meglio con iteratori ad accesso casuale.
Secondo http://www.cplusplus.com/reference/std/iterator/distance/ , poiché si vec.begin()
tratta di un iteratore ad accesso casuale , il metodo della distanza utilizza l' -
operatore.
Quindi la risposta è, dal punto di vista delle prestazioni, è la stessa, ma forse usare distance()
è più facile da capire se qualcuno dovrebbe leggere e capire il tuo codice.
Userei la -
variante std::vector
solo per - è abbastanza chiaro cosa si intende e la semplicità dell'operazione (che non è altro che una sottrazione del puntatore) è espressa dalla sintassi ( distance
, dall'altro lato, suona come pitagora sul prima lettura, no?). Come sottolinea UncleBen, -
funge anche da asserzione statica nel caso in cui vector
venga accidentalmente cambiato in list
.
Inoltre, penso che sia molto più comune - non ho numeri per dimostrarlo, però. Argomento principale: it - vec.begin()
è più breve nel codice sorgente - meno lavoro di battitura, meno spazio consumato. Come è chiaro che la risposta giusta alla tua domanda si riduce a una questione di gusti, questo può anche essere un argomento valido.
Ecco un esempio per trovare "tutte" le occorrenze di 10 insieme all'indice. Ho pensato che questo sarebbe stato di qualche aiuto.
void _find_all_test()
{
vector<int> ints;
int val;
while(cin >> val) ints.push_back(val);
vector<int>::iterator it;
it = ints.begin();
int count = ints.size();
do
{
it = find(it,ints.end(), 10);//assuming 10 as search element
cout << *it << " found at index " << count -(ints.end() - it) << endl;
}while(++it != ints.end());
}