c++c++11stliteratorerase

Why do associative containers have an erase overload with non-const iterator argument?


C++11 changed std::vector::erase to take a const_iterator instead of an iterator. The same thing applies to std::deque and std::list, while std::forward_list came in C++11 with erase_after, which also takes a const_iterator.

In contrast, std::set::erase kept its iterator overload and C++11 simply added the const_iterator one. The same thing applies to all associative containers: std::map, std::multiset, and std::multimap all kept the pre-C++11 iterator overload while std::unordered_set, std::unordered_map, std::unordered_multiset, and std::unordered_multimap all were introduced with both iterator and const_iterator overloads.

In fact, for all four set classes, iterator and const_iterator may very well be the same type.

So why the discrepancy? In addition to the inconsistency with the non-associative containers, there is also an inconsistency with the range erase overloads, which were all changed with C++11 to take a pair of const_iterators instead of a pair of iterators. Since an iterator must be convertible to a const_iterator, there is no need to have all four possible combinations of parameters for the range erase. Similarly, there is no need to have "all two combinations" for the single-value erase, so why keep the iterator overload?


Solution

  • Originally in C++11 the old iterator overload was replaced by the const_iterator one for all of these containers.

    However, the associative containers have always had additional erase overloads that take a key type as parameter. Sequence containers like std::vector and others do not have additional overloads of that kind.

    So, if you add the const_iterator overload and remove the iterator overload, and iterator and const_iterator are not the same type, then there is a chance that overload resolution becomes ambiguous where it wasn't before C++11, e.g. if the key type has a constructor from iterator.

    Therefore the resolution of LWG issue 2059 added the old iterator overloads back as a defect report. For the unordered associative containers added with C++11 these were probably added in the same way so that there isn't an unnecessary interface difference between the two kinds of containers.