2015-07-09 11 views
6

Sto attraversando un vettore con auto (codice allegato). Mentre sto attraversando, aggiungo anche alcuni elementi sul retro. Non mi aspettavo l'uscita che ho ottenuto.Comportamento insolito con auto mentre si attraversa un vettore dinamico

#include <iostream> 
#include <vector> 
using namespace std; 

vector <int> dynamic_vector; 

void access() 
{ 
    for (auto i : dynamic_vector) { 
     if (i == 3) { 
      dynamic_vector.push_back(4); 
      dynamic_vector.push_back(5); 
     } 
     cout << i << endl; 
    } 
} 

int main() { 
    dynamic_vector.push_back(1); 
    dynamic_vector.push_back(2); 
    dynamic_vector.push_back(3); 
    access(); 
    return 0; 
} 

uscita:

1 
2 
3 

mi aspettavo tutti i numeri da 1 a 5 sarà ottenere stampati. Non sono in grado di capire come attraversare con l'auto funziona?

+0

Re * Mi aspettavo che tutti i numeri da 1 a 5 vengano stampati * - Mi aspetterei demoni nasali, me stesso. Questo è un comportamento indefinito, ei demoni nasali sono il risultato canonico di invocare un comportamento indefinito. –

risposta

5

Questo è chiamato Range-based for loop.

6.5.4 $ 1 La gamma-based per la dichiarazione [stmt.ranged]:

In ogni caso, una serie-based per dichiarazione equivale a

{ 
    auto && __range = range-init; 
    for (auto __begin = begin-expr, 
      __end = end-expr; 
     __begin != __end; 
     ++__begin) { 
    for-range-declaration = *__begin; 
    statement 
    } 
} 

Nota del pseudocodice equivalente, __end (e __begin) verrà impostato una sola volta all'inizio del ciclo. Nel tuo caso, dopo lo push_back all'ultimo loop, gli iteratori potrebbero non essere validi. Se sì, l'incremento e il compendio su di essi dipenderanno dall'implementazione. Ciò significa che, come una delle possibilità, __end e __begin rimarranno gli stessi e il conteggio dei cicli non cambierà.

+1

Il risultato dipende dalla particolare implementazione degli iteratori.Ad esempio, l'iteratore può memorizzare il riferimento all'oggetto vettoriale e l'indice dell'elemento anziché memorizzare solo un puntatore. L'iteratore finale può essere uno speciale end_of_vector iteratore. –

+0

@AndreyNasonov Sì, in pratica si tratta di un problema di dipendenza dell'implementazione. – songyuanyao

+0

@songyuanyao È un comportamento definito dall'implementazione o non definito? La mia lettura dello standard sarebbe che è UB, ma non sono sicuro perché non sono riuscito a trovare una buona definizione di iteratore non valido. La cosa migliore che ho trovato è che un iteratore non valido può essere un singolare iteratore e supporta sostanzialmente i compiti. – Jens

5

In aggiunta al problema indicato dalla risposta di songyuanyao, il codice che si presenta è un comportamento non definito. Innanzitutto, è possibile che il vettore debba essere riallocato a causa di uno push_back, quindi tutti gli iteratori vengono invalidati e quindi l'incremento della variabile di ciclo è un comportamento non definito.

Guardando the documentation for push_back:

Se le nuove dimensioni() è maggiore di capacità() allora tutti gli iteratori e riferimenti (tra cui l'iteratore past-the-end) vengono invalidate. Altrimenti solo l'iteratore passato-fine viene invalidato.

, direi che l'accodamento al vettore in un intervallo per istruzione è un comportamento indefinito in ogni caso, perché l'iteratore finale è sempre invalidato. Il range-based memorizza una copia dello end() iniziale -iterator e questo iteratore viene invalidato dopo il primo push_back. Questo corrisponde al tuo output, perché punta ancora alla fine originale del vettore a tre elementi. Tuttavia, non dovresti fare affidamento su questo comportamento.

Sfortunatamente, non sono riuscito a trovare una definizione rigida di semantica "iteratore non valido" nello standard. §24.2.1.11 dice che gli iteratori non validi possono essere singolari, ma afferma solo che il loro dereferenziamento può essere un comportamento indefinito. Non esiste una semantica per confrontarli, ma dato che un'implementazione per vettori è quella di utilizzare il successivo indirizzo di memoria che segue la memoria interna, e quell'indirizzo cambia quando il vettore si rialloca, direi che il ciclo è un comportamento indefinito.

Problemi correlati