2009-06-29 12 views
50

Qualcuno può dirmi come incrementare l'iteratore di 2?Come incrementare un iteratore di 2?

iter++ disponibile - devo fare iter+2? Come posso raggiungere questo obiettivo?

+4

A giudicare dalla gamma di risposte, potrebbe essere necessario chiarire la tua domanda. – teabot

+0

Sì. Che tipo di iteratore è? Mostra un po 'di codice. –

risposta

7

è possibile utilizzare il 'assegnazione con l'aggiunta' operatore

iter += 2; 
+0

Mi chiedevo se ++ iter ++ avrebbe funzionato, ma penso che sarebbe solo confuso. – Xetius

+1

Cosa succederà se l'iteratore punta attualmente sull'ultimo elemento? Dove indicherà dopo l'incremento? – sharptooth

+3

@Xetius: non dovresti farlo. È un comportamento indefinito. – Naveen

80

std::advance(iter, 2);

Questo metodo funziona per iteratori che non sono iteratori ad accesso casuale, ma può ancora essere specializzate per l'attuazione di essere non meno efficiente di iter += 2 quando utilizzato con iteratori ad accesso casuale.

+0

Cosa succederà se l'iteratore punta attualmente sull'ultimo elemento? Dove indicherà dopo l'incremento? Ho provato con VC++ - solo avanzamenti e confronti con vector :: end() restituisce false dopo. Questo è il modo giusto per comportamento indefinito, suppongo. – sharptooth

+1

Sì, se stai andando a fare std :: advance con '2' o + = 2 o due '++' senza cercare 'end' nel mezzo, allora hai bisogno di una garanzia esterna che sei non andando ad andare oltre il passato. (Ad esempio, potresti * sapere * che stai iterando attraverso gli elementi pari (su base zero) di una raccolta che è garantita per avere un numero pari di elementi.) –

+0

qual è la differenza tra next (iter, 2) e next (iter, 2) – m1350

18

http://www.cplusplus.com/reference/std/iterator/advance/

std::advance(it,n); 

dove n è 2 nel tuo caso.

La bellezza di questa funzione è che, se "si" è un iteratore ad accesso casuale, il digiuno

it += n 

operazione viene utilizzata (cioè vettore < ,,> :: iterator). In caso contrario, la sua resa al

for(int i = 0; i < n; i++) 
    ++it; 

(vale a dire l'elenco < ..> :: iterator)

-5

La risposta molto semplice:

++++iter 

La risposta lunga:

è davvero dovrebbe ottenere utilizzato per scrivere ++iter anziché iter++. Quest'ultimo deve restituire (una copia di) il vecchio valore, che è diverso dal nuovo valore; questo richiede tempo e spazio.

Nota che l'incremento del prefisso (++iter) prende un valore e restituisce un valore, mentre l'incremento postfisso (iter++) prende un valore e restituisce un valore.

+5

Comportamento non definito se 'iter' è un puntatore raw (che possono essere alcuni tipi di iteratore). '++ esso; ++ it; "andrebbe bene. –

+0

Cattiva idea e non è molto leggibile. –

+1

Per favore dimmi che questa non è una risposta seria. – Axle

4

Se non si sa se si hanno abbastanza elementi successivi nel contenitore o no, è necessario verificare la fine del contenitore tra ogni incremento. Né ++ né std :: advance lo faranno per te.

if(++iter == collection.end()) 
    ... // stop 

if(++iter == collection.end()) 
    ... // stop 

È anche possibile eseguire il rollover della propria funzione di avanzamento sicuro.

Se sei sicuro di non andare oltre la fine, allora std :: advance (iter, 2) è la soluzione migliore.

8

Se non si dispone di un lvalue modificabile di un iteratore, o si desidera ottenere una copia di un dato iteratore (lasciando l'originale invariato), quindi C++ 11 viene fornito con nuove funzioni di supporto - std::next/std::prev:

std::next(iter, 2);   // returns a copy of iter incremented by 2 
std::next(std::begin(v), 2); // returns a copy of begin(v) incremented by 2 
std::prev(iter, 2);   // returns a copy of iter decremented by 2 
+0

Se ho un iteratore come questo: 'map :: iterator iter; per (iter = variations.begin(); iter! = Variations.end(); iter ++) { map :: iterator it_tmp = std :: next (iter, 1); // incrementa di 1 it_tmp = std :: next (iter, 2); // incrementa di 2 } ' Will ** iter ** essere incrementato di 2? o * iter * interesserà solo it_tmp? –

+0

@HaniGoc Solo it_tmp – metamorphosis

1

possiamo usare sia anticipo così come accanto. Ma c'è una differenza tra i due. "advance" modifica il suo argomento e non restituisce nulla.Così, può essere utilizzato come:

vector<int> v; 
v.push_back(1); 
v.push_back(2); 
auto itr = v.begin(); 
advance(itr, 1);   //modifies the itr 
cout << *itr<<endl  //prints 2 

"next" restituisce una copia modificata del iteratore

vector<int> v; 
v.push_back(1); 
v.push_back(2); 
cout << *next(v.begin(), 1) << endl; //prints 2 
0

Supponendo dimensione elenco non sia un multiplo pari passo è necessario evitare overflow:

static constexpr auto step = 2; 

// Guard against invalid initial iterator. 
if (!list.empty()) 
{ 
    for (auto it = list.begin(); /*nothing here*/; std::advance(it, step)) 
    { 
     // do stuff... 

     // Guard against advance past end of iterator. 
     if (std::distance(it, list.end()) > step) 
      break; 
    } 
} 

A seconda dell'implementazione della raccolta, il calcolo della distanza può essere molto lento. Di seguito è ottimale e più leggibile. La chiusura potrebbe essere cambiato a un modello di servizio con il valore della lista end passato per riferimento const:

const auto advance = [&](list_type::iterator& it, size_t step) 
{ 
    for (size_t i = 0; it != list.end() && i < step; std::next(it), ++i); 
}; 

static constexpr auto step = 2; 

for (auto it = list.begin(); it != list.end(); advance(it, step)) 
{ 
    // do stuff... 
} 

Se non c'è loop:

static constexpr auto step = 2; 
auto it = list.begin(); 

if (step <= list.size()) 
{ 
    std::advance(it, step); 
} 
Problemi correlati