Ответ 1
Это не компилируется, потому что container::iterator
и container::const_iterator
являются двумя разными типами, и единственная (однопараметрическая) версия стирания: iterator erase(iterator);
Не принимать значение const_iterator
можно рассматривать как дефект в стандарте языка: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2350.pdf
Нет особых причин для этого ограничения. Итератор используется только для для указания позиции в (модифицируемом) контейнере, и ни в случае insert
, либо erase
не является "клиентом" измененного итератора (в случае erase
он просто концептуально выходит из существования, что является нормальной задачей для объектов const).
Текущий стандарт указывает на путаницу между "константой итератора и константой контейнера" (как и другие ответы здесь), и кажется, что const_iterator
может стать приемлемым для erase
в С++ 0x.
В качестве обходного пути вы можете достоверно получить iterator
из const_iterator
, потому что контейнер должен быть изменен в первую очередь.
Функция ниже компилируется только для итераторов произвольного доступа, так как это может быть слишком медленным, чтобы сделать это с другими типами итераторов.
#include <vector>
template <class Container>
typename Container::iterator to_mutable_iterator(Container& c, typename Container::const_iterator it)
{
return c.begin() + (it - c.begin());
}
int main()
{
int arr[] = {1, 5, 2, 5, 3, 4, 5, 1};
std::vector<int> vec(arr, arr + sizeof(arr) / sizeof(*arr));
for (std::vector<int>::const_iterator it = vec.begin(); it != vec.end(); ) {
//if (*it = 5) { //const_iterator prevents this error
if (*it == 5) {
it = vec.erase(to_mutable_iterator(vec, it));
}
else {
++it;
}
}
}
Однако лучше переструктурировать код, чтобы вам в первую очередь не нужен const_iterator
. В этом случае было бы лучше использовать алгоритм std::remove
. Если вам нужно выполнить больше не мутирующих действий перед стиранием, вы можете извлечь их в отдельный метод и т.д.