Qual è la differenza tra const_iterator e non-const iterator nel C ++ STL?

Qual è la differenza tra un const_iterator e un iterator e dove utilizzeresti l’uno sull’altro?

const_iterator s non ti permette di cambiare i valori a cui puntano, l’ iterator normale lo fa.

Come con tutte le cose in C ++, preferisci sempre const , a meno che non ci sia una buona ragione per usare iteratori regolari (cioè vuoi usare il fatto che non sono const per cambiare il valore puntato).

Dovrebbero essere praticamente auto-esplicativi. Se l’iteratore punta a un elemento di tipo T, const_iterator punta a un elemento di tipo ‘const T’.

È fondamentalmente equivalente ai tipi di puntatore:

 T* // A non-const iterator to a non-const element. Corresponds to std::vector::iterator T* const // A const iterator to a non-const element. Corresponds to const std::vector::iterator const T* // A non-const iterator to a const element. Corresponds to std::vector::const_iterator 

Un iteratore const fa sempre riferimento allo stesso elemento, quindi l’iteratore stesso è const. Ma l’elemento a cui punta non deve essere const, quindi l’elemento a cui punta può essere modificato. Un const_iterator è un iteratore che punta a un elemento const, quindi mentre l’iteratore stesso può essere aggiornato (incrementato o decrementato, ad esempio), l’elemento a cui punta non può essere modificato.

Purtroppo, molti dei metodi per i contenitori STL utilizzano come parametri i iteratori anziché i costitutori . Quindi se hai un const_iterator , non puoi dire “inserisci un elemento prima dell’elemento a cui questo iteratore punta” (dicendo che una cosa del genere non è concettualmente una violazione const, secondo me). Se vuoi farlo comunque, devi convertirlo in un iteratore non const usando std :: advance () o boost :: next () . Per esempio. boost :: next (container.begin (), std :: distance (container.begin (), the_const_iterator_we_want_to_unconst)) . Se container è una lista std :: , allora il tempo di esecuzione per quella chiamata sarà O (n) .

Quindi la regola universale per aggiungere const ovunque sia “logico” farlo è meno universale quando si tratta di contenitori STL.

Tuttavia, i contenitori boost prendono const_iterators (ad esempio boost :: unordered_map :: erase ()). Quindi quando usi i contenitori boost puoi essere “const-aggressivo”. A proposito, qualcuno sa se o quando verranno riparati i container STL?

Usa const_iterator quando puoi, usa iteratore quando non hai altra scelta.

Esempi minimi

Gli iteratori non const consentono di modificare ciò che indicano:

 std::vector v{0}; std::vector::iterator it = v.begin(); *it = 1; assert(v[0] == 1); 

Gli iteratori di Const non:

 const std::vector v{0}; std::vector::const_iterator cit = v.begin(); // Compile time error: cannot modify container with const_iterator. //*cit = 1; 

Come mostrato sopra, v.begin() è const sovraccarico e restituisce iterator o const_iterator seconda della const_iterator della variabile contenitore:

  • In che modo begin () sa quale tipo di restituzione restituire (const o non-const)?
  • come funziona l’overloading delle funzioni const e non const?

Un caso comune in cui compare const_iterator è quando this viene utilizzato all’interno di un metodo const :

 class C { public: std::vector v; void f() const { std::vector::const_iterator it = this->v.begin(); } void g(std::vector::const_iterator& it) {} }; 

const rende this const, che rende this->v const.

Di solito puoi dimenticartene con l’ auto , ma se inizi a trasmettere quegli iteratori in giro, dovrai pensare a loro per le firme dei metodi.

Molto simile a const e non-const, puoi convertire facilmente da non-const a const, ma non viceversa:

 std::vector v{0}; std::vector::iterator it = v.begin(); // non-const to const. std::vector::const_iterator cit = it; // Compile time error: cannot modify container with const_iterator. //*cit = 1; // Compile time error: no conversion from const to no-const. //it = ci1; 

Quale usare: analogo a const int vs int : preferisci gli iteratori const ogni volta che puoi usarli (quando non hai bisogno di modificare il contenitore con loro), per documentare meglio la tua intenzione di leggere senza modificare.

(come altri hanno detto) const_iterator non ti permette di modificare gli elementi a cui punta, questo è utile all’interno dei metodi della class const. Permette anche di esprimere il tuo intento.

ok lascia che ti spieghi con un esempio molto semplice prima senza usare iteratore costante, considera che abbiamo raccolta di raccolta casuale di numeri casuali “randomData”

  for(vector::iterator i = randomData.begin() ; i != randomData.end() ; ++i)*i = 0; for(vector::const_iterator i = randomData.begin() ; i!= randomData.end() ; ++i)cout << *i; 

Come si può vedere per la scrittura / modifica dei dati all'interno della raccolta, viene utilizzato l'iteratore normale ma per la lettura è stato utilizzato un iteratore costante. Se si tenta di utilizzare iteratore costante nel ciclo first for si otterrà un errore. Come regola empirica, utilizzare iteratore costante per leggere i dati all'interno della raccolta.