The standard library containers allow us to erase
ranges denoted by iterators first
and last
.
std::vector<foo> bar;
// first it last it
bar.erase(bar.begin(), bar.end());
The standard says that the first
iterator must be valid and dereferenceable, whereas last
only needs to be valid. However if first == last
then first
does not need to be dereferenceable because the erase
is a no-op. This means the following is legal:
bar.erase(bar.end(), bar.end());
However if I only wish to erase one element rather than a range the iterator must be valid and dereferenceable making the following undefined behaviour:
bar.erase(bar.end());
Why isn't this just a no-op? Is it an oversight by the standards committee that will be addressed in a future revision of the language or is it a deliberate design decision that I'm not seeing the point of?
As far as I can see it provides no benefits but creates extra headaches when performing something like the following:
bar.erase(std::find(bar.begin(), bar.end(), thing));
C++ has a habit of leaving any extra work out in its standard library, also known as "You don't pay for what you don't use". In this case, the single iterator version would need to compare the iterator to the end iterator. For the majority of cases, where this check is redundant, this is extra work that isn't being used, albeit a small bit of work.
erase(iterator it):
if it != end: // we can't avoid this check now
// erase element
In the case of the overload taking a range, it stops naturally before the end. A naive implementation might be as follows:
erase(iterator first, iterator last):
while first != last:
erase(first++);
It needs some way of knowing when to stop erasing. In some cases, it could be smarter, such as memmove
ing a block of memory to overwrite the erased memory without ever branching, but that would only happen in specific scenarios.
Also note that it's much easier to build the checked version from this than the other way around:
checked_erase(Container cont, iterator it):
if it != cont.end():
cont.erase(it);