Vettori STL C ++: ottieni iteratore dall'indice?


201

Quindi, ho scritto un sacco di codice che accede agli elementi in un vettore stl mediante index [], ma ora ho bisogno di copiare solo una parte del vettore. Sembra che vector.insert(pos, first, last)sia la funzione che voglio ... tranne che ho solo il primo e l'ultimo come ints. Esiste un modo carino per ottenere un iteratore di questi valori?



Se non sbaglio, nessuna delle risposte fa alcun controllo dei limiti, il che potrebbe essere un problema. In particolare, i documenti std :: Advance affermano che il comportamento non è definito se lo si utilizza per superare i limiti del contenitore sottostante.
Martin Pecka,

Risposte:


293

Prova questo:

vector<Type>::iterator nth = v.begin() + index;

4
In generale, è possibile utilizzare la stessa aritmetica con gli iteratori STL che con i puntatori. Sono progettati per essere intercambiabili quando si utilizzano algoritmi STL.
Vincent Robert,

18
@VincentRobert: viceversa. I puntatori sono implementazioni valide degli iteratori casuali STL, la categoria più potente. Ma altre categorie meno potenti come gli iteratori diretti non supportano la stessa aritmetica.
MSalter

6
Vorrei aggiungere altri cinque centesimi a questa risposta e raccomandarestd::next(v.begin(), index)
stryku,

88

come menzionato da @dirkgently ( v.begin() + index )bello e veloce per i vettori

ma il modo più generico e per gli iteratori ad accesso casuale funziona anche a tempo costante. std::advance( v.begin(), index )

EDIT
differenze nell'utilizzo:

std::vector<>::iterator it = ( v.begin() + index );

o

std::vector<>::iterator it = v.begin();
std::advance( it, index );

aggiunto dopo le note di @litb.


std :: anticipo non richiede un iteratore non const come primo argomento?
goldPseudo

puoi usare std :: anticipo con iteratori const e non const
bayda

1
non dovresti fidarti di msvc al riguardo. ha un'estensione non standard che lo fa accettare questo tipo di cose, tuttavia tutti gli altri compilatori si comportano in modo standard e lo rifiutano.
Johannes Schaub - litb

1
Penso che il problema sia la confusione sul significato di "const": anticipo () funzionerà felicemente su un const_iterator <T>, che è un iteratore mutabile che si riferisce a un elemento const di tipo T; non funzionerà su un oggetto iteratore che è esso stesso const (cioè "const iteratore <T>" o "iteratore <T> const").
j_random_hacker il

7
Se sai che hai a che fare con a std::vector, non ha senso usare std::advance. Ti induce solo a pensare che stai scrivendo codice indipendente dal contenitore (cosa che non fai, pensando a regole di invalidazione dell'iteratore, diverse complessità di runtime e quant'altro). L'unico caso in cui std::advanceha senso è quando scrivi tu stesso un modello che non sa con quale tipo di iteratore abbia a che fare.
Frerich Raabe,

47

Anche; auto it = std::next(v.begin(), index);

Aggiornamento: è necessario un compilatore conforme a C ++ 11x


2
Va notato che questo è il modo C ++ 11! std :: next equivale a std :: anticipo. L'uso di queste funzioni anziché l'uso dell'aritmetica semplifica notevolmente lo scambio di tipi di contenitori. Funziona anche su c-array afaik, proprio come std :: begin e std :: end.
Zoomulator

2
Va inoltre notato che std :: Advance è progettato da un idiota in quanto utilizza un riferimento come output e non il valore restituito.
Viktor Sehr,

1
per (auto it = inizio (c); it! = fine (c); avanzamento (it, n)) {...}
Zoomulator

2
Entrambi hanno i loro usi. stda :: Advance è utile per modificare l'iteratore in posizione. È un problema di prestazioni nei loop. Preferirei il prossimo in caso di incarico, come suggerisci tu. L'ho appena trovato un po 'duro affermandolo come idiota. Entrambe le funzioni sono state progettate pensando a diverse situazioni, anche se sostanzialmente sono le stesse.
Zoomulator

5
@Zoomulator: se copiare l'iteratore è un problema di prestazioni, hai problemi più grandi da affrontare.
Mooing Duck


-3

In realtà std :: vector sono pensati per essere usati come scheda C quando necessario. (Lo standard C ++ lo richiede per l'implementazione vettoriale, per quanto ne so - sostituzione dell'array in Wikipedia ) Ad esempio è perfettamente legale fare questo folow, secondo me:

int main()
{

void foo(const char *);

sdt::vector<char> vec;
vec.push_back('h');
vec.push_back('e');
vec.push_back('l');
vec.push_back('l');
vec.push_back('o');
vec.push_back('/0');

foo(&vec[0]);
}

Ovviamente, foo non deve copiare l'indirizzo passato come parametro e memorizzarlo da qualche parte, oppure è necessario assicurarsi che nel programma non venga mai inserito alcun nuovo elemento in vec o che si richieda di modificarne la capacità. O errore di segmentazione del rischio ...

Quindi nel tuo esempio porta a

vector.insert(pos, &vec[first_index], &vec[last_index]);

Mi chiedo perché abbiano deciso di sottrarsi agli iteratori se sono solo dei puntatori ... essenzialmente "nascondono" queste capacità.
Aprire il

Per coerenza? In quanto consentirebbe di rimuovere facilmente l'istanza vettoriale per qualsiasi altro tipo di contenitore nel codice.
yves Baumes,

4
& vec [i] produce un puntatore che non è necessariamente compatibile con vector <> :: iteratore. vec.begin () + ho ancora il vantaggio di essere qualsiasi iteratore definito dalla tua libreria, inclusi ad esempio gli iteratori controllati in modalità debug. Quindi, se non hai bisogno di un puntatore (per esempio per l'I / O), dovresti sempre preferire gli iteratori.
sellibitze,

@KerrekSB Dal 23.3.6.1 nella bozza standard c ++: "Gli elementi di un vettore sono memorizzati contigui, il che significa che se v è un vettore <T, allocatore> dove T è un tipo diverso da bool, allora obbedisce all'identità & v [ n] == & v [0] + n per tutti 0 <= n <v.size () "
yves Baumes

2
@yvesBaumes: non ha nulla a che fare con gli iteratori vettoriali. Tuttavia, è vero che anche i puntatori nudi sono iteratori - non sono solo iteratori vettoriali .
Kerrek SB,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.