In C++17, why do associative containers have an `erase` member function that takes (non-`const`) `iterator`?

362 views Asked by At

See, e.g., http://en.cppreference.com/w/cpp/container/map/erase

In C++03 there were three overloads:

void erase( iterator pos );
void erase( iterator first, iterator last );
size_type erase( const key_type& key );

In C++11, the first and second overloads were changed to take const_iterator so that they could be called with either iterator or const_iterator. The first overload was also improved by having it return the iterator to the element after the one erased:

iterator erase( const_iterator pos );
void erase( const_iterator first, const_iterator last );
size_type erase( const key_type& key );

In C++17, a non-const overload was re-introduced:

iterator erase( const_iterator pos );
iterator erase( iterator pos );
void erase( const_iterator first, const_iterator last );
size_type erase( const key_type& key );

Why is this needed? It was not added for the ranged erase, nor for insert, nor for any of the sequence containers such as vector, deque, and list.

1

There are 1 answers

0
Praetorian On BEST ANSWER

This was done to address LWG defect 2059. Consider the example from the link

#include <map>

struct X
{
  template<typename T>
  X(T&) {}
};

bool operator<(const X&, const X&) { return false; }

void erasor(std::map<X,int>& s, X x)
{
  std::map<X,int>::iterator it = s.find(x);
  if (it != s.end())
    s.erase(it);
}

The call to map::erase at the end is ambiguous because both map::erase(const_iterator) and map::erase(key_type const&) are equally good matches as they each require a user defined conversion.

Reintroducing the map::erase(iterator) overload fixes this problem.