5

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?

Aamir
  • 1,974
  • 1
  • 14
  • 18
Nelfeal
  • 12,593
  • 1
  • 20
  • 39

1 Answers1

6

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.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • So if `std::vector::erase` had an overload taking a value (erasing everything comparing equal, kind of like `std::multiset::erase`), then it would also need an overload taking an `iterator`, like it had prior to C++11? – Nelfeal Apr 29 '23 at 13:06
  • @Nelfeal Yes, "need" is strong, but it would be preferable since it disambiguates the call in a special case that otherwise would need an explicit conversion to `const_iterator`. – user17732522 Apr 29 '23 at 13:08