Global uniqueness. If everyone, or at least serious developers who distribute their code beyond in-house projects, adheres to that convention, it will never happen that you get name clashes when you add another third-party library to your project. Bear in mind that Java was initially propagated as a solution for code deployment anywhere, anytime (via applets and remote classloading over the internet).
Is using shared_ptr
to the backing data an unnecessary inefficiency
Yes - it forces an extra indirection and an extra allocation per element, and in multithreaded programs each increment/decrement of the reference count is extra expensive even if a given container is used only inside a single thread.
All of these might be fine, and even desirable, in some situations, but the general rule is not to impose unnecessary overheads which the user cannot avoid, even when they're useless.
Since none of these overheads are necessary, but are rather debugging niceties (and remember, incorrect iterator lifetime is a static logic bug, not some weird runtime behaviour), no-one would thank you for slowing down their correct code to catch your bugs.
So, to the original question:
should an iterator into a custom container survive the container itself being destroyed?
the real question is, should the cost of tracking all live iterators into a container, and invalidating them when the container is destroyed, be foisted on people whose code is correct?
I think probably not, although if there is some case where it's genuinely hard to manage iterator lifetimes correctly and you're willing to take the hit, a dedicated container (or container adapter) that provides this service could be added as an option.
Alternatively, switching to a debug implementation based on a compiler flag might be reasonable, but it's a much bigger and more expensive change than most that are controlled by DEBUG/NDEBUG. It's certainly a bigger change than either removing assert statements or using a debugging allocator.
I forgot to mention, but your solution of using shared_ptr
everywhere doesn't necessarily fix your bug anyway: it may merely exchange it for a different bug, namely a memory leak.
Best Answer
As far as I can tell, the reason can be found in the part of javadoc you didn't quote (emphasis below mine):
You see, the intended purpose is to allow usage while list is being modified. Possible modifications apparently include removal of the elements.
Now think of what would happen if we remove an element that would be
current()
for iterator - assuming that iterator would have a notion of current element? In this context, the way to implement it without a notion of current element makes pretty good sense to me - because that way, iterator does not have to worry about elements removal.It is important to note that javadoc does not require interface implementations to be thread safe.
What ListIterator is capable of, is handling modifications done from the same thread when iterating. Not all the iterators are like that, ConcurrentModificationException javadocs specifically warn about this: