Arhn - архитектура программирования

итератор - нет подходящей функции стирания в С++ 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 — вектор 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&) действительно странно.

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


  • const_iterator означает отсутствие изменений. 01.12.2013
  • @chris const_iterator означает отсутствие изменений через этот итератор. Если вы хотите вызвать erase, вам уже нужен неконстантный способ доступа к контейнеру. Итератор просто указывает позицию для изменения, поэтому ограничение было снято в C++11. 01.12.2013
  • Я предполагаю, что этот вопрос является дубликатом: stackoverflow.com/q/15987893/420683 Вам понадобится более свежая версия библиотека C++; Насколько я знаю, сейчас это исправлено (SVN), но я не знаю, с какой версии. 01.12.2013
  • @DyP, ах, хорошая мысль. 01.12.2013
  • Не совсем уверен в том, что означает ваш комментарий. После erase(it) ни в коем случае нельзя делать ++it. 01.12.2013

Ответы:


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. (EDIT: Хорошо, очевидно, что С++ 11 добавил такой способ, но libstdС++ этого не сделал. поддержите его немедленно.) Вот что означает часть 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) в этой коллекции становятся непригодными. Стандартная терминология для этого заключается в том, что erase делает недействительными итераторы. (Причина этого в том, что std::vector ведет себя в основном как большой буфер, выделенный в куче, и вызов resize для вектора позволяет сделать эквивалент realloc(1) для буфера, а вызов erase является разрешено вызывать resize (потому что, если вы erase половину элементов в векторе, вы, вероятно, ожидаете, что выделение кучи соответственно уменьшится).)

Итак, то, что вы пытаетесь сделать, не сработает при использовании этого наивного подхода с циклом for. Вам нужно использовать стандартный алгоритм, а именно 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; это действительно типобезопасный процесс, который вызывает конструкторы перемещения и деструкторы по мере необходимости. vector знает, что в целом небезопасно memcpy использовать произвольные объекты в C++.

01.12.2013

2

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

30.11.2013
Новые материалы

Коллекции публикаций по глубокому обучению
Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

Представляем: Pepita
Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

Советы по коду Laravel #2
1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

3 способа решить квадратное уравнение (3-й мой любимый) -
1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

Создание VR-миров с A-Frame
Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

Демистификация рекурсии
КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..