confrontare gli iteratori da diversi contenitori

È legale confrontare gli iteratori da diversi contenitori?

std::vector foo; std::vector bar; 

L’espressione foo.begin() == bar.begin() produce un comportamento falso o indefinito?

(Sto scrivendo un iteratore personalizzato e sono incappato in questa domanda mentre implementavo l’ operator== .)

Se si considera la bozza C ++ 0x:

§ 24.2.1

Un iteratore j è chiamato raggiungibile da un iteratore i se e solo se esiste una sequenza finita di applicazioni dell’espressione ++ i che rende i == j. Se j è raggiungibile da i, si riferiscono a elementi della stessa sequenza.

§ 24.2.5

Il dominio di == per gli iteratori forward è quello degli iteratori sulla stessa sequenza sottostante.

Dato che RandomAccessIterator deve soddisfare tutti i requisiti imposti da ForwardIterator , il confronto tra iteratori di contenitori diversi non è definito.

Comportamento indefinito per quanto ne so. In VS 2010 con

 /* * to disable iterator checking that complains that the iterators are incompatible (come from * different containers :-) */ #define _HAS_ITERATOR_DEBUGGING 0 std::vector vec1, vec2; std::vector::iterator it1 = vec1.begin(); std::vector::iterator it2 = vec2.begin(); if (it1 == it2) { std::cout << "they are equal!!!"; } 

In questo caso, il test di uguaglianza restituisce true :-), poiché i contenitori sono vuoti e il membro _Ptr degli iteratori sono entrambi nullptr.

Chissà che la tua implementazione faccia le cose in modo diverso e il test restituisca false :-).

MODIFICARE:

Vedi la lista delle librerie attive della libreria standard C ++ "446. Iterator ugality between different containers". Forse qualcuno può controllare lo standard per vedere se il cambiamento è stato adottato?

Probabilmente no visto che è nella lista delle questioni attive, quindi Charles Bailey, che ha risposto anche a questo, ha ragione è un comportamento non specificato.

Quindi immagino che il comportamento possa differire (almeno teoricamente) tra diverse implementazioni e questo è solo un problema.

Il fatto che con il debug di iteratore abilitato nell'implementazione STL che viene fornito con i controlli VS sono in atto per questo caso esatto (iteratori provenienti da contenitori diversi) almeno per me ancora una volta che i confronti devono essere evitati ogni volta che è ansible.

Non è ansible confrontare direttamente iteratori da contenitori diversi. Un iteratore è un object che usa lo stato interno di un contenitore per attraversarlo; semplicemente non ha senso confrontare l’interno di un contenitore con un altro.

Tuttavia, se gli iteratori risultanti da container.begin() sono disponibili, può essere opportuno confrontare gli iteratori in base al conteggio degli oggetti attraversati da begin() al valore corrente di iteratore. Questo viene fatto usando std::distance :

 int a = std::distance(containerA.begin(), iteratorA); int b = std::distance(containerB.begin(), iteratorB); if (a  b) { /* ... */ } 

Senza più contesto, è difficile giudicare se questo potrebbe risolvere il tuo problema o meno. YMMV.

Credo che sia un comportamento non specificato (C ++ 03). std::vector iterators sono iteratori ad accesso casuale e il comportamento di == è definito nei requisiti per gli iteratori forward.

== è una relazione di equivalenza

Si noti che questo è un requisito per un tipo, quindi deve essere applicabile (in questo caso) a qualsiasi coppia valida (dereferenziabile o diversa) std::vector::iterator s. Credo che questo significhi == deve darti una risposta true / false e non può causare UB.

– Se a e b sono uguali, allora a e b sono entrambi dereferenziabili o altrimenti nessuno dei due è dereferenziabile.

Viceversa, un iteratore dereferenziabile non può essere paragonato ad un iteratore che non è dereferenziabile.

– Se aeb sono entrambi dereferenziabili, quindi a == b se e solo se * a e * b sono lo stesso object.

Notare la mancanza di requisiti su a == b per due iteratori che non sono dereferenziabili. Finché == è transitivo (se a.end() == b.end() e b.end() == c.end() allora a.end() == c.end() ), riflessivo ( a.end() == a.end() ) e simmetrico (se a.end() == b.end() allora b.end() == a.end() ) non importa se alcuni, tutti o nessuno end() iteratori di diversi contenitori sono uguali.

Nota, inoltre, che questo è in contrasto con < . < è definito in termini di b - a , dove a e b sono entrambi iteratori ad accesso casuale. Una pre-condizione dell'esecuzione di b - a è che ci deve essere un valore Distance n tale che a + n == b che richiede a e b di essere iteratori nello stesso intervallo.

No. Se fosse legale, ciò implicherebbe che i puntatori non sarebbero iteratori.

ISO / IEC 14882: 2003 (E) 5.10.1

Gli operatori == (uguale a) e! = (Non uguale a) hanno le stesse restrizioni semantiche, le conversioni e il tipo di risultato degli operatori relazionali ad eccezione del loro risultato di precedenza e valore di verità inferiore. [..] I puntatori agli oggetti o alle funzioni dello stesso tipo (dopo le conversioni del puntatore) possono essere confrontati per l’uguaglianza. Due puntatori dello stesso tipo sono uguali se e solo se entrambi sono nulli, entrambi puntano alla stessa funzione, oppure entrambi rappresentano lo stesso indirizzo (3.9.2).

Risultati di simulazione su XCode (3.2.3):

 #include  #include  int main() { std::vector  a,aa; std::vector  b; if( a.begin() == aa.begin() ) std::cout << "\n a.begin() == aa.begin() \n" ; a.push_back(10) ; if( a.begin() != aa.begin() ) std::cout << "\n After push back a.begin() != aa.begin() \n" ; // Error if( a.begin() == b.begin() ) return 0; } 

Produzione :

a.begin () == aa.begin ()
Dopo aver respinto a.begin ()! = Aa.begin ()

Non ho i requisiti per gli iteratori di input dallo standard 100%, ma da lì su (forward / bidirezionali / iteratori di accesso casuale) non ci sono requisiti sul dominio di ==, quindi deve restituire risultati falsi in una relazione di equivalenza . Non puoi però fare o sottrarre su iteratori da diversi contenitori.

Modifica: Non deve restituire falso, deve generare una relazione di equivalenza, ciò consente a .begin() di due contenitori vuoti di comparare uguali (come mostrato in un’altra risposta). Se gli iteratori sono dereferenziabili, deve essere mantenuto a == b => *a == *b . Non è ancora un comportamento indefinito.