итератор — нет подходящей функции стирания в c ++ 11

Я не могу объяснить это поведение:

for (vector<File>::const_iterator it = this->files.begin(); it != this->files.end(); ++it) {
if (...) erase(it); // break after, no need of ++it in else branch
}

где File — мой собственный класс (стандартный std), а this-> files — вектор файлов

когда я компилирую код, который я получаю (см. строка 2)

Path.cpp: In member function ‘void Path::rmFile(File&)’:
Path.cpp:190:24: error: no matching function for call to ‘std::vector<File>::erase(std::vector<File>::const_iterator&)’
Path.cpp:190:24: note: candidates are:
In file included from /usr/include/c++/4.7/vector:70:0,
from Path.h:5,
from Path.cpp:1:
/usr/include/c++/4.7/bits/vector.tcc:135:5: note: std::vector<_Tp, _Alloc>::iterator     std::vector<_Tp, _Alloc>::erase(std::vector<_Tp, _Alloc>::iterator) [with _Tp = File; _Alloc =     std::allocator<File>; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<File*,     std::vector<File> >; typename std::_Vector_base<_Tp, _Alloc>::pointer = File*]
/usr/include/c++/4.7/bits/vector.tcc:135:5: note:   no known conversion for argument 1     from ‘std::vector<File>::const_iterator {aka __gnu_cxx::__normal_iterator<const File*,     std::vector<File> >}’ to ‘std::vector<File>::iterator {aka __gnu_cxx::__normal_iterator<File*,     std::vector<File> >}’
/usr/include/c++/4.7/bits/vector.tcc:147:5: note: std::vector<_Tp, _Alloc>::iterator     std::vector<_Tp, _Alloc>::erase(std::vector<_Tp, _Alloc>::iterator, std::vector<_Tp,     _Alloc>::iterator) [with _Tp = File; _Alloc = std::allocator<File>; std::vector<_Tp,     _Alloc>::iterator = __gnu_cxx::__normal_iterator<File*, std::vector<File> >; typename     std::_Vector_base<_Tp, _Alloc>::pointer = File*]
/usr/include/c++/4.7/bits/vector.tcc:147:5: note:   candidate expects 2 arguments, 1 provided
make: *** [Path.o] Error 1

даже доктор говорит, что все в порядке, но ошибка нет соответствующей функции для вызова std :: vector :: erase (std :: vector :: const_iterator&) действительно странно.

Мне действительно нужно иметь возможность удалить элемент вектора с помощью итератора. Кто-нибудь может мне помочь, пожалуйста?
Так заранее.

1

Решение

У вас есть три ошибки здесь.

for (vector<File>::const_iterator it = this->files.begin(); it != this->files.end(); ++it) {
if (...) erase(it); // break after, no need of ++it in else branch
}

Первая ошибка в том, что вы неправильно вырезали и вставляли свой код в StackOverflow. То, что вы хотели вставить, было

for (vector<File>::const_iterator it = this->files.begin(); it != this->files.end(); ++it) {
if (...) this->files.erase(it); // break after, no need of ++it in else branch
}

Второй баг это то, о чем вас предупреждает компилятор: нет способа изменить коллекцию через const_iterator, (РЕДАКТИРОВАТЬ: Хорошо, очевидно, C ++ 11 добавил такой способ, но libstdc ++ не поддерживал его сразу.) Вот что const_ часть означает! Если вы хотите изменить коллекцию, используйте простой старый iterator:

for (vector<File>::iterator it = this->files.begin(); it != this->files.end(); ++it) {
if (...) this->files.erase(it); // LOOK OUT, THERE'S STILL A BUG
}

Третий баг это когда ты звонишь std::vector::erase в коллекции все итераторы (и const_iterators) в эту коллекцию становятся непригодный. Стандартная терминология для этого такова, что erase делает недействительными итераторы. (Причина этого заключается в том, что std::vector ведет себя в основном как большой буфер, выделенный кучей, и вызов resize на векторе разрешено делать эквивалент realloc(1) в буфере, и вызов erase разрешено звонить resize (потому что если вы erase половина элементов в векторе, вы, вероятно, ожидаете, что выделение кучи соответственно уменьшится).)

Итак, что вы пытаетесь сделать не будет работать используя этот наивный подход для цикла. Что вам нужно сделать, это использовать стандартный алгоритм, а именно remove_if:

#include <algorithm>

auto predicate = [](const File& f) { return f.ShouldBeErasedOrWhatever(); }
auto newEndIterator = std::remove_if(this->files.begin(), this->files.end(), predicate);
this->files.erase(newEndIterator, this->files.end());  // erase everything after "newEndIterator"

замещать f.ShouldBeErasedOrWhatever() с чем угодно «...«находится в оригинальном коде. Теперь у вас есть действительный идиоматический C ++ 11, который делает правильные вещи — без ошибок!


(1) — Обратите внимание на «эквивалент realloc«Конечно, это не действительно realloc; это действительно типобезопасный процесс, который при необходимости вызывает move-constructors и destructors. vector знает, что это вообще не безопасно memcpy произвольные объекты в C ++.

4

Другие решения

Предполагая, что ваш пример кода неверен, и это действительно так files.erase(it), затем const_iterator версия была добавлена ​​только в C ++ 11, что, похоже, у вас нет, так как вы не используете auto,

2