Doesn't erasing std::list::iterator invalidate

2019-02-17 23:57发布

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?

标签: c++ list stl erase
5条回答
老娘就宠你
2楼-- · 2019-02-18 00:50

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.

查看更多
Bombasti
3楼-- · 2019-02-18 00:50

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.)

查看更多
爷的心禁止访问
4楼-- · 2019-02-18 00:55

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.

查看更多
聊天终结者
5楼-- · 2019-02-18 00:56

"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.

查看更多
闹够了就滚
6楼-- · 2019-02-18 00:58

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

查看更多
登录 后发表回答