Doesn't erasing std::list::iterator invalidates the iterator and destroys the object?

此生再无相见时 提交于 2019-12-01 03:38:14

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!