2015-02-09 12 views
5

È illegale incrementare l'iteratore di accesso casuale fuori intervallo? Si scopre che l'implementazione di Visual C++ del vettore attiva l'asserzione di debug.Incremento iteratore fuori intervallo

std::vector<int> foo(5); 
auto iter = foo.begin(); 
iter += 10; 

Questo dovrebbe essere legale con i puntatori finché la posizione della memoria non viene valutata.

Modifica: apparentemente è illegale anche con i puntatori.

+2

la responsabilità di mantenere l'iteratore all'interno dell'intervallo dipende interamente dal chiamante. –

+1

Sì, questo è legale con un puntatore. Ma quello che hai è un iteratore. –

+0

@AlexeyAndronov Lo standard dice che è un comportamento indefinito. Sia per gli iteratori che per i puntatori. –

risposta

2

Questo comportamento non è definito, il che significa che può accadere qualsiasi cosa, incluso segfault, o ciò che si è verificato o qualsiasi altra cosa. Fondamentalmente, eri solo fortunato che non si è schiantato (o sfortunato, in base al punto di vista).

La lingua non richiede la verifica degli accessi iteratore, poiché ciò richiederebbe un controllo in fase di esecuzione. C++ di solito cerca di evitare inutili sovraccarichi di run-time, lasciando al programmatore la possibilità di eseguire qualsiasi controllo sia necessario.

La maggior parte delle piattaforme moderne utilizza la memoria virtuale a pagine, fornendo protezione della memoria con una granularità di alcuni kilobyte. Ciò significa che spesso c'è una memoria accessibile dopo un blocco assegnato (come quello gestito da std :: vector), nel qual caso gli accessi fuori dall'intervallo semplicemente calpesteranno quella memoria.

Visual Studio sta cercando di aiutare a rimuovere il codice pericoloso. In linea di principio un puntatore potrebbe puntare ovunque se non lo si deniteri, ma gli iteratori sono un'astrazione di livello superiore e hanno la capacità di rilevare se il dereferenziamento sarebbe valido e quindi aumentare gli errori di runtime. Visual Studio ha eseguito questa operazione con vector<T>::iterator almeno dal VS 2007.

+2

Com'è che l'iteratore avanzato è UB? Per quanto ne so, topicstarter ha ragione nella sua ultima affermazione –

+1

@AlexeyAndronov È un comportamento indefinito perché lo standard dice che è un comportamento indefinito.La maggior parte delle moderne implementazioni della libreria standard causerà un errore di asserzione; se il tuo non lo fa, e stai compilando senza ottimizzazione, richiedi un rimborso –

+0

@JamesKanze, ok, grazie, non lo so :) –

3

È un comportamento non definito. Entrambi con iteratori e con puntatori. Con gli iteratori , è probabile che si verifichi un errore di asserzione, almeno con il debug dell'iter attivato. Con i puntatori, probabilmente non eseguirà lo nella maggior parte delle architetture moderne, ma ci sono state macchine su che potrebbe innescarsi a trap. Non è necessario accedere alla posizione della memoria , basta creare il puntatore, in caso si verifichi un comportamento non definito su .

EDIT:

Dalla standard (§5.7/5, emphesis aggiunto):

Quando viene aggiunto o sottratto un puntatore un'espressione che ha tipo integrale, il risultato è il tipo dell'operando del puntatore. Se l'operando del puntatore punta a un elemento di un oggetto array e l'array è sufficientemente grande, il risultato punta a un elemento di offset dall'elemento originale in modo tale che la differenza tra gli indici degli elementi di matrice risultante e originale sia uguale l'espressione integrale. In altre parole, se l'espressione P punta all'elemento i-esimo di un oggetto array , le espressioni (P) + N (equivalentemente, N + (P)) e (P) -N (dove N ha il valore n) indicano rispettivamente gli elementi i + n-th e i -n-th dell'oggetto array, purché esistenti. Inoltre, se l'espressione P di punta all'ultimo elemento di un oggetto di matrice, l'espressione (P) +1 punta oltre l'ultimo elemento dell'oggetto di matrice, e se l'espressione Q indica uno dopo l'ultimo elemento di un oggetto array oggetto, l'espressione (Q) -1 punta sull'ultimo elemento dell'array oggetto.Se sia l'operando del puntatore che il risultato puntano agli elementi di lo stesso oggetto matrice o uno dopo l'ultimo elemento dell'oggetto array, la valutazione non deve produrre un overflow; altrimenti, il comportamento non è definito.

La regola corrispondente per iteratori ad accesso casuale (gli unici che supporto aggiunta) si sviluppa-su più sezioni: l'operatore += è definito in termini di ripetute ++ (per la semantica — è richiesto per avere una complessità di tempo costante), e ++ ha il requisito che è predeferenziabile con “. post: r è dereferenziabile o r è passato-alla-fine. ” (dalla definizione di input iterators, che viene ereditato dagli iteratori di inoltro, che viene ereditato dagli iteratori bidirezionali , che viene ereditato da iteratori di accesso casuale).

Problemi correlati