Я не могу объяснить это поведение:
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&) действительно странно.
Мне действительно нужно иметь возможность удалить элемент вектора с помощью итератора. Кто-нибудь может мне помочь, пожалуйста?
Так заранее.
У вас есть три ошибки здесь.
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_iterator
s) в эту коллекцию становятся непригодный. Стандартная терминология для этого такова, что 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 ++.
Предполагая, что ваш пример кода неверен, и это действительно так files.erase(it)
, затем const_iterator
версия была добавлена только в C ++ 11, что, похоже, у вас нет, так как вы не используете auto
,