2016-07-01 27 views
6

In C++, perché non è possibile utilizzare '>' o '<' per confrontare InputIterators, ForwardIterators e BidirectionalIterators? Tuttavia, possiamo confrontare RandomAccessIterators con '>' o '<', ad esempio std :: vector. Qual è la ragione di questo?Domande sugli iteratori C++

Inoltre, perché non è possibile coutuire il contenuto degli iteratori? come "cout < < itr < < endl;" non funzionerebbe Qual è la ragione di questo? Gli iteratori sono molto simili ai puntatori, ma possiamo cout puntatori ma non iteratori, perché?

In generale, qual è la differenza intrinseca tra iteratori e puntatori? Ero solito pensare che fossero simili, ma credo di doverlo capire per arrivare al prossimo livello di comprensione del C++.

Domanda n. 2: Grazie a tutti per le risposte fantastiche. Ho ancora una domanda riguardo agli iteratori. Perché C++ stampa qualcosa come "50397953" quando l'iteratore va fuori limite? Non dovrebbe stampare qualcosa come NULL o '\ 0'?

+0

Quanto tempo ci vorrà per valutare 'itr1 Beta

+0

Grazie Beta. Questa è una risposta naturale! – Thenewstockton

risposta

5

std::list<T> ha iteratori bidirezionali e non ha alcun senso richiedere che siano confrontabili. Non è nemmeno chiaro come sarebbe possibile implementare std::list<T> per essere conforme a tale requisito. Tuttavia, poiché gli iteratori di accesso casuale supportano la sottrazione, è ovvio che possiamo confrontarli.

Perché non è possibile stampare il valore di un iteratore? In generale, spetta all'autore sostenere questa operazione. Molti iteratori sono fondamentalmente implementati come puntatori o wrapper attorno ai puntatori --- fornendo operator<< per loro non darebbe all'utente alcun beneficio che non potrebbero ottenere semplicemente stampando l'indirizzo dell'oggetto puntato.

Per quanto riguarda la differenza tra iteratori e puntatori, i puntatori agli oggetti sono un tipo specifico di iteratore di accesso casuale, ma gli iteratori possono anche essere di tipo classe purché soddisfino i requisiti dell'iteratore.

+0

Grazie Brian. Ma perché non fornirebbe all'operatore << un vantaggio per l'utente? L'indirizzo di memoria non è qualcosa che i programmatori esaminano continuamente? – Thenewstockton

+2

@Thenewstockton Puoi semplicemente 'std :: cout << & * it' se lo vuoi. Nella mia esperienza, non è abbastanza spesso utile fornire una stenografia. – Brian

+0

@Thenewstockton nella mia esperienza, mentre faccio le cose come suggerite voi - fornendo un sovraccarico dell'operatore per gli iteratori su misura - spesso sembra che sarà più utile di quanto non lo sarà nel lungo periodo. Questo perché qualsiasi innovazione sintattica tattica che si aggiunge finisce con il lavorare contro la strategia semantica della convenzione iteratore: ci sono poche aggiunte di sintassi a [la nozione di un iteratore] (http://en.cppreference.com/w/cpp/iterator) che, a mio parere, non devono lavorare contro il concetto generale, che come è stato sopra menzionato è: "una generalizzazione dei puntatori". Fondamentalmente. – fish2000

3

C'è una spiegazione rigida, formale e pratica.

La rigida, formale spiegazione

Perché è così che è specificato in C++.

La spiegazione pratica

Un vettore viene sempre memorizzata nella memoria contigua, per definizione. Un iteratore è, più o meno un puntatore. Pertanto, confrontando gli attuali indirizzi di memoria sottostanti è possibile definire quale puntatore è "minore" o "maggiore" rispetto all'altro puntatore.

D'altra parte, ogni elemento di una lista o di un insieme può essere memorizzato ovunque. Ogni elemento è istanziato in modo indipendente. Un iteratore per un particolare elemento nell'elenco potrebbe fare riferimento a una posizione di memoria numericamente inferiore rispetto a un iteratore diverso per un altro elemento nella stessa lista, ma l'elemento effettivo potrebbe essere dopo l'altro elemento, nella lista effettiva. Dati due iteratori in una lista, non è possibile determinare immediatamente quale sia più vicino all'inizio o alla fine della lista. Si noti che l'inserimento e la rimozione di elementi in un elenco non invalida gli iteratori di elenchi esistenti, poiché ciascun elemento nell'elenco viene istanziato in modo indipendente.

Il motivo pratico per cui non è possibile utilizzare gli iteratori con operator<< su un std::ostream è perché, ovviamente, questo sovraccarico non è definito.Nota: puoi sempre effettuare le seguenti operazioni:

cout << &*itr << endl; 

Questo formatterà l'indirizzo di memoria effettivo dell'elemento di riferimento. Ma questo è di dubbia utilità comunque. È per lo più privo di significato.

+0

Grazie Sam. Ma perché STL non definirebbe il sovraccarico? So che uno può stampare l'indirizzo usando & * itr. Tuttavia, non è naturale supportare "cout << itr << endl;" ? Penso che abbia a che fare con la differenza tra i puntatori e gli iteratori, ma non so davvero perché? Per favore aiuto! – Thenewstockton

+0

@Thenewstockton: Perché pensi che sarebbe naturale? Non mi sembra così. –

+0

@BenjaminLindley Bene, questo è quello che penso: puoi fare "cout << ptr << end;" , quindi è naturale fare "cout << itr << endl;" ma questo non funzionerebbe. – Thenewstockton

1

Non risponderò alla prima parte della tua domanda perché sono d'accordo con quanto è stato detto, ma ti risponderò le altre due parti aggiungendo alcuni dettagli. Sto iniziando dalla parte più facile da spiegare.

In generale, qual è la differenza intrinseca tra iteratori e puntatori? Ero solito pensare che fossero simili, ma credo di doverlo capire per arrivare al prossimo livello di comprensione del C++.

Gli iteratori sono la generalizzazione dei puntatori.

Potete anche guardare in quel iterator implementation on github

Inoltre, perché non possiamo cout contenuti iteratori? come "cout < < itr < < endl;" non funzionerebbe Qual è la ragione di questo? Gli iteratori sono molto simili ai puntatori, ma possiamo cout puntatori ma non iteratori, perché?

Allora, che cosa sta accadendo all'interno, mi pare di capire, è che iteratore è una classe che ha un campo di memorizzazione di un puntatore ad un oggetto. L'operatore '*' viene sovrascritto e restituisce il valore memorizzato all'indirizzo dei puntatori.