Iteratori

Un iteratore è un oggetto in grado di eseguire l'iterazione sugli elementi di un contenitore della libreria standard C++ e fornire accesso ai singoli elementi. Tutti i contenitori della libreria standard C++ forniscono iteratori che consentono agli algoritmi di accedere ai relativi elementi in maniera standard, senza doversi preoccupare del tipo di contenitore in cui sono archiviati gli elementi.

È possibile usare gli iteratori in modo esplicito usando funzioni membro e globali, begin() ad esempio e end() e , ad esempio ++ e -- per spostarsi avanti o indietro. È anche possibile usare gli iteratori in modo implicito con un ciclo range-for o ,per alcuni tipi di iteratore, l'operatore []di pedice .

Nella libreria standard C++ l'inizio di una sequenza o di un intervallo corrisponde al primo elemento. La fine di una sequenza o di un intervallo è sempre definita come un elemento dopo l'ultimo elemento. Le funzioni begin globali e end restituiscono iteratori a un contenitore specificato. Il ciclo iteratore esplicito standard su tutti gli elementi in un contenitore è simile al seguente:

vector<int> vec{ 0,1,2,3,4 };
for (auto it = begin(vec); it != end(vec); it++)
{
    // Access element using dereference operator
    cout << *it << " ";
}

La stessa operazione può essere eseguita in modo più semplice con un ciclo range-for:

for (auto num : vec)
{
    // no dereference operator
    cout << num << " ";
}

Le categorie di iteratori disponibili sono cinque. Per la potenza, le categorie sono riepilogate in ordine crescente come:

  • Output. Un iteratore X di output può scorrere in avanti su una sequenza usando l'operatore ++ e può scrivere un elemento una sola volta usando l'operatore * .

  • Input. Un iteratore X di input può scorrere in avanti su una sequenza usando l'operatore ++ e può leggere un elemento qualsiasi numero di volte usando l'operatore * . È possibile confrontare gli iteratori di input usando gli == operatori e != . Dopo aver incrementato qualsiasi copia di un iteratore di input, nessuna delle altre copie può essere confrontata, dereferenziata o incrementata in un secondo momento.

  • Avanti. Un iteratore X in avanti può scorrere in avanti su una sequenza usando l'operatore ++ e può leggere qualsiasi elemento o scrivere elementi non const qualsiasi numero di volte usando l'operatore * . È possibile accedere ai membri degli elementi usando l'operatore -> e confrontare gli iteratori in avanti usando gli == operatori e != . È anche possibile eseguire più copie di un iteratore in avanti, ciascuna delle quali può essere dereferenziata e incrementata in modo indipendente. Un iteratore in avanti inizializzato senza riferimento a un contenitore viene chiamato iteratore in avanti Null. Gli iteratori in avanti null risultano sempre uguali.

  • Bidirezionale. Un iteratore bidirezionale può assumere il posto di un iteratore X in avanti. È tuttavia possibile decrementare anche un iteratore bidirezionale, come in --X, X--o (V = *X--). È possibile accedere ai membri degli elementi e confrontare gli iteratori bidirezionali nello stesso modo degli iteratori in avanti.

  • Accesso casuale. Un iteratore X ad accesso casuale può assumere il posto di un iteratore bidirezionale. Con un iteratore ad accesso casuale, è possibile usare l'operatore [] pedice per accedere agli elementi. È possibile usare gli +operatori , += -e -= per spostarsi avanti o indietro in un numero specificato di elementi e per calcolare la distanza tra iteratori. È possibile confrontare gli iteratori bidirezionali usando ==, !=, <>, <=, e >=.

Tutti gli iteratori possono essere assegnati o copiati. Si presuppone che siano oggetti leggeri e vengono spesso passati e restituiti per valore, non per riferimento. Si noti anche che nessuna delle operazioni descritte in precedenza può generare un'eccezione quando viene eseguita su un iteratore valido.

La gerarchia di categorie di iteratore può essere riepilogata mostrando tre sequenze. Per accedere a una sequenza in sola scrittura, è possibile usare:

iteratore di output
-> iteratore in avanti
-> iteratore bidirezionale
-> iteratore ad accesso casuale

La freccia destra significa "può essere sostituita da". Qualsiasi algoritmo che chiama un iteratore di output dovrebbe funzionare correttamente con un iteratore in avanti, ad esempio, ma non l'altro modo.

Per eseguire l'accesso di sola lettura a una sequenza, è possibile usare:

iteratore di input
-> iteratore in avanti
-> iteratore bidirezionale
-> iteratore ad accesso casuale

In questo caso, un iteratore di input è il più debole di tutte le categorie.

Infine, per accedere a una sequenza in lettura/scrittura, è possibile usare:

iteratore in avanti
-> iteratore bidirezionale
-> iteratore ad accesso casuale

Un puntatore a oggetto può sempre fungere da iteratore ad accesso casuale, quindi può essere usato come qualsiasi categoria di iteratore se supporta l'accesso corretto in lettura/scrittura alla sequenza che definisce.

Un iteratore Iterator diverso da un puntatore all'oggetto deve anche definire i tipi di membri necessari per la specializzazione iterator_traits<Iterator>. Questi requisiti possono essere soddisfatti derivando Iterator dall'iteratore della classe di base pubblica.

È importante comprendere le promesse e le limitazioni di ogni categoria di iteratore per vedere in che modo gli iteratori vengono usati dai contenitori e dagli algoritmi nella libreria standard C++.

Nota

È possibile evitare l'utilizzo di iteratori in modo esplicito utilizzando cicli range-for. Per altre informazioni, vedere Istruzione For basata su intervallo.

Microsoft C++ offre ora iteratori controllati e iteratori di debug per assicurarsi di non sovrascrivere i limiti del contenitore. Per altre informazioni, vedere Iteratori verificati e Supporto degli iteratori di debug.

Vedi anche

Informazioni di riferimento per la libreria standard C++
Thread Safety in the C++ Standard Library (Sicurezza dei thread nella libreria standard C++)