问题
Why does the following print 2
?
list<int> l;
l.push_back( 1 );
l.push_back( 2 );
l.push_back( 3 );
list<int>::iterator i = l.begin();
i++;
l.erase( i );
cout << *i;
I know what erase
returns, but I wonder why this is OK? Or is it undefined, or does it depend on the compiler?
回答1:
Yes, it's undefined behaviour. You are dereferencing a kind of wild pointer. You shouldn't use the value of i
after erase
.
And yes, erase
destructs the object pointed to. However, for POD types destruction doesn't do anything.
erase
doesn't assign any special "null" value to the iterator being erased, the iterator is just not valid any more.
回答2:
"destroying" an object means its memory is reclaimed and its content might be altered (mainly if the hand-written destructor do so, and possibly as a result of storing free-memory-related stuff in place). list::erase returns you a new iterator that you should use instead of the one that was passed as argument (I'd be tempted to make i = l.erase(i);
an habbit).
In no way do destruction imply that memory is swept, wiped out. Previously valid location are still valid in most cases from the CPU's point of view (ie. it can fetch values), but can't be relied on because other operation may recycle that location for any purpose at any time.
You're unlikely to see *i
throwing a segfault, imho -- although that might happen with more complex types that use pointers, but you might see it having new values.
Other collections might have a more previsible behaviour than list. IIrc, a vector would compact the storage area so the previous value would only be seen by further dereferencing i
in rare cases.
回答3:
Seems like iterator still points to this memory....
If you would write something to this block,
maybe next time *i would throw segmentation fault..
sorry for speculation though
回答4:
Since you are dealing with a linked list, the elements of the list need not to be right "behind" each other in memory. If you would try the same thing with a vector, you would likely (since the behavior is undefined) experience
cout << *i
to be printed as 2.
However, this is not a very safe way of programming. So once you erase an iterator make sure not to use it again, unless you initialize it again with begin() or end() etc.
回答5:
Try compiling your code with the correct options, with a good compiler,
then running it. (With VC++, /D_DEBUG /EHs /MDd
seems to be
sufficient. With g++, -D_GLIBCXX_CONCEPT_CHECKS -D_GLIBCXX_DEBUG
-D_GLIBCXX_DEBUG_PEDANTIC
, at least. Both compilers need even more
options in general.) It should crash. (It does when I tried it.)
来源:https://stackoverflow.com/questions/5274025/doesnt-erasing-stdlistiterator-invalidates-the-iterator-and-destroys-the-ob