Sembra che tu stia pensando a un iteratore "non valido" come solo uno che provocherebbe un arresto anomalo se utilizzato, ma la definizione dello standard è più ampia. Include la possibilità che l'iteratore possa ancora essere tranquillamente dereferenziato, ma non punta più all'elemento a cui ci si aspetta che punti. (Questo è un caso speciale dell'osservazione che "comportamento indefinito" non corrisponde a significa "il tuo programma si blocca immediatamente", ma può anche significare "il tuo programma calcola silenziosamente il risultato sbagliato" o anche "non si verifica nulla di questo implementazione ")
E 'più facile dimostrare perché questo è un problema con erase
:.
#include <vector>
#include <iostream>
int main(void)
{
std::vector<int> a { 0, 1, 2, 3, 4, 4, 6 };
for (auto p = a.begin(); p != a.end(); p++) // THIS IS WRONG
if (*p == 4)
a.erase(p);
for (auto p = a.begin(); p != a.end(); p++)
std::cout << ' ' << *p;
std::cout << '\n';
}
su implementazioni tipiche del C++ questo programma non andrà in crash, ma stamperà 0 1 2 3 4 6
, piuttosto che 0 1 2 3 6
come probabilmente inteso, perché cancellando il f irst 4
invalidatop
- avanzandolo sopra il secondo 4
.
L'implementazione di C++ potrebbe avere una speciale modalità di "debug" in cui questo programma si arresta in modo anomalo durante l'esecuzione.. Ad esempio, con GCC 4.8:
$ g++ -std=c++11 -W -Wall test.cc && ./a.out
0 1 2 3 4 6
ma
$ g++ -std=c++11 -W -Wall -D_GLIBCXX_DEBUG test.cc && ./a.out
/usr/include/c++/4.8/debug/safe_iterator.h:307:error: attempt to increment
a singular iterator.
Objects involved in the operation:
iterator "this" @ 0x0x7fff5d659470 {
type = N11__gnu_debug14_Safe_iteratorIN9__gnu_cxx17__normal_iteratorIPiNSt9__cxx19986vectorIiSaIiEEEEENSt7__debug6vectorIiS6_EEEE (mutable iterator);
state = singular;
references sequence with type `NSt7__debug6vectorIiSaIiEEE' @ 0x0x7fff5d659470
}
Aborted
capiscono che il programma provoca un comportamento indefinito in entrambi i casi. È solo che le conseguenze del comportamento indefinito sono più drammatiche nella modalità di debug.
Dite che con la dereferenziazione standard C++ un simile iteratore non porta a un comportamento indefinito? –
@ TobiasBrüll no, secondo lo standard C++ porta a un comportamento indefinito (secondo lo standard C++). Il comportamento non definito più comune, se la capacità non viene modificata, è che si ottiene l'elemento che ora ha lo stesso offset a cui l'ultimo iteratore ha fatto riferimento, nella pratica effettiva. Ma piuttosto che aggiungere verbage su "iteratori che cambiano ciò a cui si riferiscono" che legherebbe quale implementazione è usata e renderà lo standard più difficile da leggere (heh), in pratica dicono che gli iteratori si riferiscono sempre alla stessa cosa, o diventano non validi. Ci sono ottimizzazioni che un compilatore può fare a causa di ciò, in teoria. – Yakk
@ TobiasBrüll: No, è ancora un comportamento non definito. Questo non significa che ti capita di fare un incidente. –