简体   繁体   中英

Does std::vector::erase() really invalidate the iterator at the point of erase?

I was playing around to understand iterator invalidation rule. However, when I run following code in c++14 compiler, output really confuses me..

std::vector<int> test = {1,2,3};
auto it = test.begin() + 1;
test.erase(it);
std::cout << *it << std::endl;

output = 3 shouldn't it invalidate at this point? Why it seems to jump to the next pos? Many thanks in advance

Dereferencing an invalidated iterator has undefined results. Your program may crash, it may stop with a runtime error or break in the debugger (if you are running a debug build with a debug version of the STL with iterator debugging/validation) and it may "seem to work", ie, deliver the value that was erased from the collection.

This is because iterators MAY be implemented as just pointers. This is not necessarily the case, but defining behavior in this situation as undefined allows such an efficient and simple implementation. Invalid iterators implemented as pointers MAY still point to a valid memory location, which MAY still contain the value it previously contained, even though it is logically no longer part of the data structure (collection) it was a part of. There is no validation code which checks if the iterator is valid when it is dereferenced (except sometimes in debug builds).

This is both one of the characteristics strengths and one of the weaknesses of C++, as it gives your program better performance at the cost of stability and security in case your program does something undefined (due to a bug or using unvalidated user input).

When describing iterator invalidation, the C++ standard takes the simplifying assumption that iterators refer to elements, and a valid iterator value always refers to same element. Invalidating references, pointers or iterators to an element all follow the same rules. (The exception is the end iterator).

Clearly references or pointers to the erased element are invalidated by a call to erase, thus under the standard's simple rules so are all iterators. It could have described what new element must be moved in place abd substituted what iterators refer to, but the writers of the standard chise not to go there. They instead simply dictated the iterator was invalid.

Because it is invalid, dereferencing it or doing anything but destroying it or assigning anitger iterator to it is declared undefined behaviour.

In theory this permits a myriad of optimization opportunities, but I am unaware of any compiler that exploits them. At best compilers add debug checks at this time.

So dereferencing it "works", but being UB the result is inheritly fragile. Future compilers could assume you do not do this and cause arbitrary side effects, including time travel (I am not joking; current compilers can cause UB to time travel and corrupt program state before the UB occurs ; in particular, int overflow optimizations).

Every current compiler uses at best thinly wrapped pointers for vector iterators. But relying on non-standard mandated behaviour quirks of the implementation is a bad plan, when doing it correctly only requires a bit more work. If you find a case where assuming that behaviour would be highly useful, I encourage you to write a proposal to define that behaviour using your use case as motivation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM