2013-07-05 12 views
9

Secondo lo standard C++, chiamare push_back() su un vettore invalida l'iteratore se la nuova dimensione del vettore cresce oltre la sua capacità, ma su un elenco non invalida mai gli iteratori. Ora considerare i seguenti frammenti di codice:semantica di end() iteratore per vettore e lista

1.

vector<int> v{1,2,3}; 
v.reserve(100); 
for (int i: v) { 
    v.push_back(i); 
} 

2.

list<int> l{1,2,3}; 
for (int i: l) { 
    l.push_back(i); 
} 

ho provato con gcc 4.8 e ha scoperto che il codice 1 finiture con v essere {1,2,3,1,2,3}, ma il codice 2 piste in un ciclo infinito. La spiegazione mi sembra abbastanza semplice: l'iteratore end() di vector punta a una posizione di memoria e, dal it is only evaluated once during a range based for loop, si ferma quando raggiunge il terzo elemento del vettore. D'altra parte, list probabilmente ha un qualche tipo di token nullo come iteratore finale, che viene sempre posizionato dopo l'ultimo elemento, quindi il ciclo non lo raggiungerà mai.

Mentre i risultati sembrano semplici, la mia domanda è: cosa dice lo standard a riguardo? Si suppone che sia così in tutte le implementazioni di libreria standard, o questo comportamento non è definito? Cosa devo aspettarmi quando si scrive un ciclo che può chiamare push_back() in un contenitore di questo tipo (che di solito preferisco evitare comunque)?

+0

Immagino che lo Standard non abbia molto da dire a riguardo. È permesso, è legale, è solo un ciclo infinito –

+0

@AndyProwl Penso che lo standard abbia qualcosa da dire: è necessario che sia un ciclo infinito. (Se non è un ciclo infinito con 'vector', è perché c'è un comportamento indefinito, quindi qualsiasi cosa l'implementazione è legale.) –

+0

@JamesKanze: Beh, è ​​lo stesso che intendevo dire. Il PO ha scritto un ciclo infinito legale, non c'è nulla che lo standard abbia da dire su quella particolare situazione (parlando ovviamente dell'esempio della lista). –

risposta

5

Non credo che lo standard è molto esplicito, ma in generale, end significa end, e se si inserisce elementi di là la posizione corrente in un ciclo, non si otterrà mai lì.

Naturalmente, il primo ciclo, con vector, è indefinito comportamento, poiché inserto (e cancellare) invalida tutti iteratori a o oltre la posizione di inserimento, anche se non c'è riallocazione. E l'iteratore finale sarà sempre oltre il punto di inserimento .

+0

Secondo cppreference.com, gli iteratori in 'vector' vengono invalidati solo se la dimensione supera la capacità. http://en.cppreference.com/w/cpp/container/vector/push_back Questo riflette lo standard correttamente o dice che possono essere invalidati a qualsiasi chiamata a 'push_back'? – petersohn

+0

@petersohn: Cppreference dice letteralmente "... Altrimenti no iteratori e riferimenti sono invalidati." Questo è chiaramente sbagliato. Dal punto di vista puramente "fisico" si può capire la loro logica, ma le specifiche linguistiche richiedono un approccio più di alto livello. Tutti gli iteratori e i riferimenti che fanno riferimento a elementi "spostati" vengono considerati non validi, anche se potrebbero comunque fare riferimento a posizioni di memoria valide. – AnT

+1

@petersohn Secondo lo standard (§23.3.6.5): "[...] Se non viene eseguita la riallocazione , tutti gli iteratori e i riferimenti precedenti allo rimangono validi nel punto di inserimento. "(Se non è garantito che rimanga valido, non sono validi. Si tratta di un errore evidente al del sito che si cita –

Problemi correlati