I am surprised at just how many cases aren’t just T*, but happily in not using T* they ensure that unlike T* there is Zero Overhead (tm) :D
Something I’ve honestly wanted is for the exact opposite of this (which is obviously not possible due to the API problems the article talks about).
Many years ago I added release mode bounds checks in the webkit collection interfaces, and that worked well as using iterator based enumeration was miserable, so few people used it. This was great because in addition to being bounds checked, index based enumeration is safe against the collection backing store being reallocated.
Alas when C++ added enumerator syntax everyone started implicitly begin() and end(), which means pointer comparisons which loses both bounds safety as end() is only called once, and safety against a reallocation of the underlying buffer.
Alas when C++ added enumerator syntax everyone started implicitly begin() and end(), which means pointer comparisons which loses both bounds safety as end() is only called once, and safety against a reallocation of the underlying buffer.
This depends on the underlying collection. There is no requirement with range-based for loops that begin and end return the same type, they just need to be != comparable. You can make end return something that takes a pointer to the collection and computes the end, and even something that returns false to operator!= on the type that you return from begin if the collection has been mutated.
Objective-C’s fast enumeration requires that you throw an exception if the collection is mutated during iteration. This is typically implemented by keeping a version in the container and incrementing it on mutation, then comparing it to a value in the iterator. C++ gives you the building blocks for doing this. You can also use iterators with opaque data types (i.e. abstract base classes that are representation agnostic and have subclasses optimised for different uses) with amortised lookup cost if your virtual function called by the iterator is able to collect a range of things that you then iterate over. I’ve actually implemented C++ iterators that look a lot like Objective-C fast enumeration (though with a lot more type safety) in this way.
I know that you can create your own iterator classes for begin/end, but the standard collections don’t do that (and doing so would be an abi break, albeit one that I suspect would not have significant impact).
The bigger issue I had is that the performance hit was pretty terrible with the obvious safe implementation:
There is an issue with this implementation in that a change in vector size isn’t handled, to do so correctly requires additional checks which makes it even slower.
I am surprised at just how many cases aren’t just T*, but happily in not using T* they ensure that unlike T* there is Zero Overhead (tm) :D
Something I’ve honestly wanted is for the exact opposite of this (which is obviously not possible due to the API problems the article talks about).
Many years ago I added release mode bounds checks in the webkit collection interfaces, and that worked well as using iterator based enumeration was miserable, so few people used it. This was great because in addition to being bounds checked, index based enumeration is safe against the collection backing store being reallocated.
Alas when C++ added enumerator syntax everyone started implicitly begin() and end(), which means pointer comparisons which loses both bounds safety as end() is only called once, and safety against a reallocation of the underlying buffer.
This depends on the underlying collection. There is no requirement with range-based for loops that
begin
andend
return the same type, they just need to be != comparable. You can makeend
return something that takes a pointer to the collection and computes the end, and even something that returnsfalse
tooperator!=
on the type that you return frombegin
if the collection has been mutated.Objective-C’s fast enumeration requires that you throw an exception if the collection is mutated during iteration. This is typically implemented by keeping a version in the container and incrementing it on mutation, then comparing it to a value in the iterator. C++ gives you the building blocks for doing this. You can also use iterators with opaque data types (i.e. abstract base classes that are representation agnostic and have subclasses optimised for different uses) with amortised lookup cost if your
virtual
function called by the iterator is able to collect a range of things that you then iterate over. I’ve actually implemented C++ iterators that look a lot like Objective-C fast enumeration (though with a lot more type safety) in this way.I know that you can create your own iterator classes for begin/end, but the standard collections don’t do that (and doing so would be an abi break, albeit one that I suspect would not have significant impact).
The bigger issue I had is that the performance hit was pretty terrible with the obvious safe implementation:
There is an issue with this implementation in that a change in vector size isn’t handled, to do so correctly requires additional checks which makes it even slower.